xref: /openbsd-src/sbin/isakmpd/ui.c (revision 8500990981f885cbe5e6a4958549cacc238b5ae6)
1 /*	$OpenBSD: ui.c,v 1.35 2003/11/06 16:12:08 ho Exp $	*/
2 /*	$EOM: ui.c,v 1.43 2000/10/05 09:25:12 niklas Exp $	*/
3 
4 /*
5  * Copyright (c) 1998, 1999, 2000 Niklas Hallqvist.  All rights reserved.
6  * Copyright (c) 1999, 2000, 2001, 2002 H�kan Olsson.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * This code was written under funding by Ericsson Radio Systems.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <errno.h>
40 
41 #include "sysdep.h"
42 
43 #include "conf.h"
44 #include "connection.h"
45 #include "doi.h"
46 #include "exchange.h"
47 #include "init.h"
48 #include "isakmp.h"
49 #include "log.h"
50 #include "monitor.h"
51 #include "sa.h"
52 #include "timer.h"
53 #include "transport.h"
54 #include "ui.h"
55 #include "util.h"
56 
57 #define BUF_SZ 256
58 
59 /* from isakmpd.c */
60 void daemon_shutdown_now (int);
61 
62 /* Report all SA configuration information. */
63 void ui_report_sa (char *cmd);
64 
65 char *ui_fifo = FIFO;
66 int ui_socket;
67 
68 /* Create and open the FIFO used for user control.  */
69 void
70 ui_init (void)
71 {
72   struct stat st;
73 
74   /* -f- means control messages comes in via stdin.  */
75   if (strcmp (ui_fifo, "-") == 0)
76     ui_socket = 0;
77   else
78     {
79       /* Don't overwrite a file, i.e '-f /etc/isakmpd/isakmpd.conf'.  */
80       if (lstat (ui_fifo, &st) == 0)
81 	if ((st.st_mode & S_IFMT) == S_IFREG)
82 	  {
83 	    errno = EEXIST;
84 	    log_fatal ("ui_init: could not create FIFO \"%s\"", ui_fifo);
85 	  }
86 
87       /* No need to know about errors.  */
88       unlink (ui_fifo);
89       if (monitor_mkfifo (ui_fifo, 0600) == -1)
90 	log_fatal ("ui_init: mkfifo (\"%s\", 0600) failed", ui_fifo);
91 
92       ui_socket = monitor_open (ui_fifo, O_RDWR | O_NONBLOCK, 0);
93       if (ui_socket == -1)
94 	log_fatal ("ui_init: open (\"%s\", O_RDWR | O_NONBLOCK, 0) failed",
95 		   ui_fifo);
96     }
97 }
98 
99 /*
100  * Setup a phase 2 connection.
101  * XXX Maybe phase 1 works too, but teardown won't work then, fix?
102  */
103 static void
104 ui_connect (char *cmd)
105 {
106   char name[81];
107 
108   if (sscanf (cmd, "c %80s", name) != 1)
109     {
110       log_print ("ui_connect: command \"%s\" malformed", cmd);
111       return;
112     }
113   LOG_DBG ((LOG_UI, 10, "ui_connect: setup connection \"%s\"", name));
114   connection_setup (name);
115 }
116 
117 /* Tear down a phase 2 connection.  */
118 static void
119 ui_teardown (char *cmd)
120 {
121   char name[81];
122   struct sa *sa;
123 
124   if (sscanf (cmd, "t %80s", name) != 1)
125     {
126       log_print ("ui_teardown: command \"%s\" malformed", cmd);
127       return;
128     }
129   LOG_DBG ((LOG_UI, 10, "ui_teardown: teardown connection \"%s\"", name));
130   connection_teardown (name);
131   while ((sa = sa_lookup_by_name (name, 2)) != 0)
132     sa_delete (sa, 1);
133 }
134 
135 /* Tear down all phase 2 connections.  */
136 static void
137 ui_teardown_all (char *cmd)
138 {
139   /* Skip 'cmd' as arg. */
140   sa_teardown_all ();
141 }
142 
143 /*
144  * Call the configuration API.
145  * XXX Error handling!  How to do multi-line transactions?  Too short arbitrary
146  * limit on the parameters?
147  */
148 static void
149 ui_config (char *cmd)
150 {
151   char subcmd[81], section[81], tag[81], value[81], tmp[81];
152   int trans = 0, items;
153 
154   if (sscanf (cmd, "C %80s", subcmd) != 1)
155     goto fail;
156 
157   trans = conf_begin ();
158   if (strcasecmp (subcmd, "set") == 0)
159     {
160       items = sscanf (cmd, "C %*s [%80[^]]]:%80[^=]=%80s %80s", section, tag,
161 		      value, tmp);
162       if (!(items == 3 || items == 4))
163 	goto fail;
164       conf_set (trans, section, tag, value, items == 4 ? 1 : 0, 0);
165     }
166   else if (strcasecmp (subcmd, "rm") == 0)
167     {
168       if (sscanf (cmd, "C %*s [%80[^]]]:%80s", section, tag) != 2)
169 	goto fail;
170       conf_remove (trans, section, tag);
171     }
172   else if (strcasecmp (subcmd, "rms") == 0)
173     {
174       if (sscanf (cmd, "C %*s [%80[^]]]", section) != 1)
175 	goto fail;
176       conf_remove_section (trans, section);
177     }
178   else
179     goto fail;
180 
181   LOG_DBG ((LOG_UI, 30, "ui_config: \"%s\"", cmd));
182   conf_end (trans, 1);
183   return;
184 
185     fail:
186   if (trans)
187     conf_end (trans, 0);
188   log_print ("ui_config: command \"%s\" malformed", cmd);
189 }
190 
191 static void
192 ui_delete (char *cmd)
193 {
194   char cookies_str[ISAKMP_HDR_COOKIES_LEN * 2 + 1];
195   char message_id_str[ISAKMP_HDR_MESSAGE_ID_LEN * 2 + 1];
196   u_int8_t cookies[ISAKMP_HDR_COOKIES_LEN];
197   u_int8_t message_id_buf[ISAKMP_HDR_MESSAGE_ID_LEN];
198   u_int8_t *message_id = message_id_buf;
199   struct sa *sa;
200 
201   if (sscanf (cmd, "d %32s %8s", cookies_str, message_id_str) != 2)
202     {
203       log_print ("ui_delete: command \"%s\" malformed", cmd);
204       return;
205     }
206 
207   if (strcmp (message_id_str, "-") == 0)
208     message_id = 0;
209 
210   if (hex2raw (cookies_str, cookies, ISAKMP_HDR_COOKIES_LEN) == -1
211       || (message_id && hex2raw (message_id_str, message_id_buf,
212 				 ISAKMP_HDR_MESSAGE_ID_LEN) == -1))
213     {
214       log_print ("ui_delete: command \"%s\" has bad arguments", cmd);
215       return;
216     }
217 
218   sa = sa_lookup (cookies, message_id);
219   if (!sa)
220     {
221       log_print ("ui_delete: command \"%s\" found no SA", cmd);
222       return;
223     }
224   LOG_DBG ((LOG_UI, 20,
225 	    "ui_delete: deleting SA for cookie \"%s\" msgid \"%s\"",
226 	    cookies_str, message_id_str));
227   sa_delete (sa, 1);
228 }
229 
230 #ifdef USE_DEBUG
231 /* Parse the debug command found in CMD.  */
232 static void
233 ui_debug (char *cmd)
234 {
235   int cls, level;
236   char subcmd[3];
237 
238   if (sscanf (cmd, "D %d %d", &cls, &level) == 2)
239     {
240       log_debug_cmd (cls, level);
241       return;
242     }
243   else if (sscanf (cmd, "D %2s %d", subcmd, &level) == 2)
244     {
245       switch (subcmd[0])
246 	{
247 	case 'A':
248 	  for (cls = 0; cls < LOG_ENDCLASS; cls++)
249 	    log_debug_cmd (cls, level);
250 	  return;
251 	}
252     }
253   else if (sscanf (cmd, "D %2s", subcmd) == 1)
254     {
255       switch (subcmd[0])
256 	{
257 	case 'T':
258 	  log_debug_toggle ();
259 	  return;
260 	}
261     }
262 
263   log_print ("ui_debug: command \"%s\" malformed", cmd);
264   return;
265 }
266 
267 static void
268 ui_packetlog (char *cmd)
269 {
270   char subcmd[81];
271 
272   if (sscanf (cmd, "p %80s", subcmd) != 1)
273     goto fail;
274 
275   if (strncasecmp (subcmd, "on=", 3) == 0)
276     {
277       /* Start capture to a new file.  */
278       if (subcmd[strlen (subcmd) - 1] == '\n')
279 	subcmd[strlen (subcmd) - 1] = 0;
280       log_packet_restart (subcmd + 3);
281     }
282   else if (strcasecmp (subcmd, "on") == 0)
283     log_packet_restart (NULL);
284   else if (strcasecmp (subcmd, "off") == 0)
285     log_packet_stop ();
286 
287   return;
288 
289  fail:
290   log_print ("ui_packetlog: command \"%s\" malformed", cmd);
291 }
292 #endif /* USE_DEBUG */
293 
294 static void
295 ui_shutdown_daemon (char *cmd)
296 {
297   if (strlen (cmd) == 1)
298     {
299       log_print ("ui_shutdown_daemon: received shutdown command");
300       daemon_shutdown_now (0);
301     }
302   else
303     log_print ("ui_shutdown_daemon: command \"%s\" malformed", cmd);
304 }
305 
306 /* Report SAs and ongoing exchanges.  */
307 void
308 ui_report (char *cmd)
309 {
310   /* XXX Skip 'cmd' as arg? */
311   sa_report ();
312   exchange_report ();
313   transport_report ();
314   connection_report ();
315   timer_report ();
316   conf_report ();
317 }
318 
319 /* Report all SA configuration information.  */
320 void
321 ui_report_sa (char *cmd)
322 {
323   /* Skip 'cmd' as arg? */
324   sa_report_all ();
325 }
326 
327 /*
328  * Call the relevant command handler based on the first character of the
329  * line (the command).
330  */
331 static void
332 ui_handle_command (char *line)
333 {
334   /* Find out what one-letter command was sent.  */
335   switch (line[0])
336     {
337     case 'c':
338       ui_connect (line);
339       break;
340 
341     case 'C':
342       ui_config (line);
343       break;
344 
345     case 'd':
346       ui_delete (line);
347       break;
348 
349 #ifdef USE_DEBUG
350     case 'D':
351       ui_debug (line);
352       break;
353 
354     case 'p':
355       ui_packetlog (line);
356       break;
357 #endif
358 
359     case 'Q':
360       ui_shutdown_daemon (line);
361       break;
362 
363     case 'R':
364       reinit ();
365       break;
366 
367     case 'S':
368       ui_report_sa (line);
369       break;
370 
371     case 'r':
372       ui_report (line);
373       break;
374 
375     case 't':
376       ui_teardown (line);
377       break;
378 
379     case 'T':
380       ui_teardown_all (line);
381       break;
382 
383     default:
384       log_print ("ui_handle_messages: unrecognized command: '%c'", line[0]);
385     }
386 }
387 
388 /*
389  * A half-complex implementation of reading from a file descriptor
390  * line by line without resorting to stdio which apparently have
391  * troubles with non-blocking fifos.
392  */
393 void
394 ui_handler (void)
395 {
396   static char *buf = 0;
397   static char *p;
398   static size_t sz;
399   static size_t resid;
400   size_t n;
401   char *new_buf;
402 
403   /* If no buffer, set it up.  */
404   if (!buf)
405     {
406       sz = BUF_SZ;
407       buf = malloc (sz);
408       if (!buf)
409 	{
410 	  log_print ("ui_handler: malloc (%lu) failed", (unsigned long)sz);
411 	  return;
412 	}
413       p = buf;
414       resid = sz;
415     }
416 
417   /* If no place left in the buffer reallocate twice as large.  */
418   if (!resid)
419     {
420       new_buf = realloc (buf, sz * 2);
421       if (!new_buf)
422 	{
423 	  log_print ("ui_handler: realloc (%p, %lu) failed", buf,
424 		(unsigned long)sz * 2);
425 	  free (buf);
426 	  buf = 0;
427 	  return;
428 	}
429       buf = new_buf;
430       p = buf + sz;
431       resid = sz;
432       sz *= 2;
433     }
434 
435   n = read (ui_socket, p, resid);
436   if (n == -1)
437     {
438       log_error ("ui_handler: read (%d, %p, %lu)", ui_socket, p,
439 	(unsigned long)resid);
440       return;
441     }
442 
443   if (!n)
444     return;
445   resid -= n;
446   while (n--)
447     {
448       /*
449        * When we find a newline, cut off the line and feed it to the
450        * command processor.  Then move the rest up-front.
451        */
452       if (*p == '\n')
453 	{
454 	  *p = '\0';
455 	  ui_handle_command (buf);
456 	  memcpy (buf, p + 1, n);
457 	  p = buf;
458 	  resid = sz - n;
459 	  continue;
460 	}
461       p++;
462     }
463 }
464