OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / freeswan / pluto / kernel_comm.c
1 /* whack communicating routines
2  * Copyright (C) 1997 Angelos D. Keromytis.
3  * Copyright (C) 1998-2001  D. Hugh Redelmeier.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * for more details.
14  *
15  * RCSID $Id: kernel_comm.c,v 1.69 2002/03/22 23:38:27 dhr Exp $
16  */
17
18 #include <stdio.h>
19 #include <stddef.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <resolv.h>
29 #include <arpa/nameser.h>       /* missing from <resolv.h> on old systems */
30
31 #include <freeswan.h>
32
33 #include "constants.h"
34 #include "defs.h"
35 #include "id.h"
36 #include "x509.h"
37 #include "connections.h"        /* needs id.h */
38 #include "whack.h"      /* needs connections.h */
39 #include "packet.h"
40 #include "demux.h"      /* needs packet.h */
41 #include "state.h"
42 #include "ipsec_doi.h"  /* needs demux.h and state.h */
43 #include "kernel.h"
44 #include "kernel_comm.h"
45 #include "log.h"
46 #include "x509.h"
47 #include "preshared.h"
48 #include "adns.h"       /* needs <resolv.h> */
49 #include "dnskey.h"     /* needs preshared.h and adns.h */
50 #include "server.h"
51 #include "kernel_alg.h"
52 #include "ike_alg.h"
53 #ifndef NO_DB_OPS_STATS
54 #define NO_DB_CONTEXT
55 #include "db_ops.h"
56 #endif
57 /* helper variables and function to decode strings from whack message */
58
59 static char *next_str
60     , *str_roof;
61
62 static bool
63 unpack_str(char **p)
64 {
65     char *end = memchr(next_str, '\0', str_roof - next_str);
66
67     if (end == NULL)
68     {
69         return FALSE;   /* fishy: no end found */
70     }
71     else
72     {
73         *p = next_str == end? NULL : next_str;
74         next_str = end + 1;
75         return TRUE;
76     }
77 }
78
79 /* bits loading keys from asynchronous DNS */
80
81 struct key_add_continuation {
82     struct adns_continuation ac;
83     int whack_fd;
84 };
85
86 static void
87 key_add_ugh(const struct id *keyid, err_t ugh)
88 {
89     char name[IDTOA_BUF];       /* longer IDs will be truncated in message */
90
91     (void)idtoa(keyid, name, sizeof(name));
92     loglog(RC_NOKEY
93         , "failure to fetch key for %s from DNS: %s", name, ugh);
94 }
95
96 static void
97 key_add_continue(struct adns_continuation *ac, err_t ugh)
98 {
99     struct key_add_continuation *kc = (void *) ac;
100
101     whack_log_fd = kc->whack_fd;
102     if (ugh != NULL)
103     {
104         key_add_ugh(&ac->id, ugh);
105     }
106     else
107     {
108         remember_public_keys(&keys_from_dns);
109     }
110     close_any(whack_log_fd);
111 }
112
113 /* Handle a kernel request. Supposedly, there's a message in
114  * the kernelsock socket.
115  */
116 void
117 whack_handle(int whackctlfd)
118 {
119     struct whack_message msg;
120     struct sockaddr_un whackaddr;
121     int whackaddrlen = sizeof(whackaddr);
122     int whackfd = accept(whackctlfd, (struct sockaddr *)&whackaddr, &whackaddrlen);
123     ssize_t n;
124
125     if (whackfd < 0)
126     {
127         log_errno((e, "accept() failed in whack_handle()"));
128         return;
129     }
130     n = read(whackfd, &msg, sizeof(msg));
131     if (n == -1)
132     {
133         log_errno((e, "read() failed in whack_handle()"));
134         close(whackfd);
135         return;
136     }
137
138     whack_log_fd = whackfd;
139
140     /* sanity check message */
141     {
142         err_t ugh = NULL;
143
144         next_str = msg.string;
145         str_roof = (char *)&msg + n;
146
147         if (next_str > str_roof)
148         {
149             ugh = builddiag("truncated message from whack: got %d bytes; expected %d.  Message ignored."
150                 , n, (int) sizeof(msg));
151         }
152         else if (msg.magic != WHACK_MAGIC)
153         {
154             ugh = builddiag("message from whack has bad magic %d; should be %d; probably wrong version.  Message ignored"
155                 , msg.magic, WHACK_MAGIC);
156         }
157         else if (!unpack_str(&msg.name)         /* string 1 */
158         || !unpack_str(&msg.left.id)            /* string 2 */
159         || !unpack_str(&msg.left.cert)          /* string 3 */
160         || !unpack_str(&msg.left.updown)        /* string 4 */
161 #ifdef VIRTUAL_IP
162         || !unpack_str(&msg.left.virt)
163 #endif
164         || !unpack_str(&msg.right.id)           /* string 5 */
165         || !unpack_str(&msg.right.cert)         /* string 6 */  
166         || !unpack_str(&msg.right.updown)       /* string 7 */
167 #ifdef VIRTUAL_IP
168         || !unpack_str(&msg.right.virt)
169 #endif
170         || !unpack_str(&msg.keyid)              /* string 8 */
171         || !unpack_str(&msg.ike)                /* string 9 */
172         || !unpack_str(&msg.esp)                /* string 10 */ 
173         || !unpack_str(&msg.dnshostname)        /* string 11 */
174         || str_roof - next_str != (ptrdiff_t)msg.keyval.len)    /* check chunk */
175         {
176             ugh = "message from whack contains bad string";
177         }
178         else
179         {
180             msg.keyval.ptr = next_str;  /* grab chunk */
181         }
182
183         if (ugh != NULL)
184         {
185             loglog(RC_BADWHACKMESSAGE, "%s", ugh);
186             whack_log_fd = NULL_FD;
187             close(whackfd);
188             return;
189         }
190     }
191
192     if (msg.whack_options)
193     {
194 #ifdef DEBUG
195         if (msg.name == NULL)
196         {
197             /* we do a two-step so that if either old or new would
198              * cause the message to print, it will be printed.
199              */
200             cur_debugging |= msg.debugging;
201             DBG(DBG_CONTROL
202                 , DBG_log("base debugging = %s"
203                     , bitnamesof(debug_bit_names, msg.debugging)));
204             cur_debugging = base_debugging = msg.debugging;
205         }
206         else if (!msg.whack_connection)
207         {
208             struct connection *c = con_by_name(msg.name, TRUE);
209
210             if (c != NULL)
211             {
212                 c->extra_debugging = msg.debugging;
213                 DBG(DBG_CONTROL
214                     , DBG_log("\"%s\" extra_debugging = %s"
215                         , c->name
216                         , bitnamesof(debug_bit_names, c->extra_debugging)));
217             }
218         }
219 #endif
220     }
221
222     /* Deleting combined with adding a connection works as replace.
223      * To make this more useful, in only this combination,
224      * delete will silently ignore the lack of the connection.
225      */
226     if (msg.whack_delete)
227     {
228         struct connection *c = con_by_name(msg.name, !msg.whack_connection);
229
230         /* note: this is a "while" because road warrior
231          * leads to multiple connections with the same name.
232          */
233         for (; c != NULL; c = con_by_name(msg.name, FALSE))
234             delete_connection(c);
235     }
236
237     if (msg.whack_deletestate)
238     {
239         struct state *st = state_with_serialno(msg.whack_deletestateno);
240
241         if (st == NULL)
242         {
243             loglog(RC_UNKNOWN_NAME, "no state #%lu to delete"
244                 , msg.whack_deletestateno);
245         }
246         else
247         {
248             delete_state(st);
249         }
250     }
251
252     if (msg.whack_connection)
253         add_connection(&msg);
254
255     /* process "listen" before any operation that could require it */
256     if (msg.whack_listen)
257     {
258         log("listening for IKE messages");
259         listening = TRUE;
260         find_ifaces();
261         load_preshared_secrets();
262     }
263     if (msg.whack_unlisten)
264     {
265         log("no longer listening for IKE messages");
266         listening = FALSE;
267     }
268
269     if (msg.whack_reread & REREAD_SECRETS)
270     {
271         load_preshared_secrets();
272     }
273
274    if (msg.whack_reread & REREAD_MYCERT)
275     {
276         load_mycert();
277     }
278
279    if (msg.whack_reread & REREAD_CACERTS)
280     {
281         load_cacerts();
282     }
283
284    if (msg.whack_reread & REREAD_CRLS)
285     {
286         load_crls();
287     }
288
289    if (msg.whack_list & LIST_PUBKEYS)
290     {
291         list_public_keys(msg.whack_utc);
292     }
293
294     if (msg.whack_list & LIST_CERTS)
295     {
296         list_certs(msg.whack_utc);
297     }
298
299     if (msg.whack_list & LIST_CACERTS)
300     {
301         list_cacerts(msg.whack_utc);
302     }
303
304     if (msg.whack_list & LIST_CRLS)
305     {
306         list_crls(msg.whack_utc);
307     }
308
309     if (msg.whack_key)
310     {
311         /* add a public key */
312         struct id keyid;
313         err_t ugh = atoid(msg.keyid, &keyid);
314
315         if (ugh != NULL)
316         {
317             loglog(RC_BADID, "bad --keyid \"%s\": %s", msg.keyid, ugh);
318         }
319         else
320         {
321             if (!msg.whack_addkey)
322                 delete_public_keys(&keyid, msg.pubkey_alg);
323
324             if (msg.keyval.len == 0)
325             {
326                 struct key_add_continuation *kc
327                     = alloc_thing(struct key_add_continuation
328                         , "key add continuation");
329                 int wfd = dup_any(whackfd);
330
331                 kc->whack_fd = wfd;
332                 ugh = start_adns_query(&keyid
333                     , NULL
334                     , T_KEY
335                     , key_add_continue
336                     , &kc->ac);
337
338                 if (ugh != NULL)
339                 {
340                     key_add_ugh(&keyid, ugh);
341                     close_any(wfd);
342                 }
343             }
344             else
345             {
346                 ugh = add_public_key(&keyid, DAL_LOCAL, msg.pubkey_alg
347                     , &msg.keyval, &pubkeys);
348                 if (ugh != NULL)
349                     loglog(RC_LOG_SERIOUS, "%s", ugh);
350             }
351         }
352     }
353
354     if (msg.whack_route)
355     {
356         if (!listening)
357             whack_log(RC_DEAF, "need --listen before --route");
358         else
359         {
360             struct connection *c = con_by_name(msg.name, TRUE);
361
362             if (c != NULL)
363             {
364                 set_cur_connection(c);
365                 if (!oriented(*c))
366                     whack_log(RC_ORIENT
367                         , "we have no ipsecN interface for either end of this connection");
368                 else if (!trap_connection(c))
369                     whack_log(RC_ROUTE, "could not route");
370                 reset_cur_connection();
371             }
372         }
373     }
374
375     if (msg.whack_unroute)
376     {
377         struct connection *c = con_by_name(msg.name, TRUE);
378
379         if (c != NULL)
380         {
381             set_cur_connection(c);
382             if (c->routing >= RT_ROUTED_TUNNEL)
383                 whack_log(RC_RTBUSY, "cannot unroute: route busy");
384             else
385                 unroute_connection(c);
386             reset_cur_connection();
387         }
388     }
389
390     if (msg.whack_initiate)
391     {
392         if (!listening)
393             whack_log(RC_DEAF, "need --listen before --initiate");
394         else
395             initiate_connection(msg.name
396                 , msg.whack_async? NULL_FD : dup_any(whackfd));
397     }
398
399     if (msg.whack_oppo_initiate)
400     {
401         if (!listening)
402             whack_log(RC_DEAF, "need --listen before opportunistic initiation");
403         else
404             initiate_opportunistic(&msg.oppo_my_client, &msg.oppo_peer_client
405                 , FALSE
406                 , msg.whack_async? NULL_FD : dup_any(whackfd));
407     }
408
409     if (msg.whack_terminate)
410         terminate_connection(msg.name);
411
412     if (msg.whack_status)
413     {
414         show_ifaces_status();
415         whack_log(RC_COMMENT, BLANK_FORMAT);    /* spacer */
416 #ifndef NO_KERNEL_ALG
417         kernel_alg_show_status();
418         whack_log(RC_COMMENT, BLANK_FORMAT);    /* spacer */
419 #endif
420 #ifndef NO_IKE_ALG
421         ike_alg_show_status();
422         whack_log(RC_COMMENT, BLANK_FORMAT);    /* spacer */
423 #endif
424 #ifndef NO_DB_OPS_STATS
425         db_ops_show_status();
426         whack_log(RC_COMMENT, BLANK_FORMAT);    /* spacer */
427 #endif
428         show_connections_status();
429         whack_log(RC_COMMENT, BLANK_FORMAT);    /* spacer */
430         show_states_status();
431     }
432
433     if (msg.whack_shutdown)
434     {
435         log("shutting down");
436         exit_pluto(0);  /* delete lock and leave, with 0 status */
437     }
438
439     whack_log_fd = NULL_FD;
440     close(whackfd);
441 }