admin.c revision 1.4
1/*	$NetBSD: admin.c,v 1.4 2005/07/12 14:15:39 manu Exp $	*/
2
3/* Id: admin.c,v 1.17 2005/01/02 08:39:09 manubsd Exp */
4
5/*
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "config.h"
35
36#include <sys/types.h>
37#include <sys/param.h>
38#include <sys/socket.h>
39#include <sys/signal.h>
40#include <sys/stat.h>
41#include <sys/un.h>
42
43#include <net/pfkeyv2.h>
44
45#include <netinet/in.h>
46#ifndef HAVE_NETINET6_IPSEC
47#include <netinet/ipsec.h>
48#else
49#include <netinet6/ipsec.h>
50#endif
51
52
53#include <stdlib.h>
54#include <stdio.h>
55#include <string.h>
56#include <errno.h>
57#include <netdb.h>
58#ifdef HAVE_UNISTD_H
59#include <unistd.h>
60#endif
61
62#include "var.h"
63#include "misc.h"
64#include "vmbuf.h"
65#include "plog.h"
66#include "sockmisc.h"
67#include "debug.h"
68
69#include "schedule.h"
70#include "localconf.h"
71#include "remoteconf.h"
72#include "grabmyaddr.h"
73#include "isakmp_var.h"
74#include "isakmp.h"
75#include "oakley.h"
76#include "handler.h"
77#include "evt.h"
78#include "pfkey.h"
79#include "ipsec_doi.h"
80#include "admin.h"
81#include "admin_var.h"
82#include "isakmp_inf.h"
83#include "session.h"
84#include "gcmalloc.h"
85
86#ifdef ENABLE_ADMINPORT
87char *adminsock_path = ADMINSOCK_PATH;
88uid_t adminsock_owner = 0;
89gid_t adminsock_group = 0;
90mode_t adminsock_mode = 0600;
91
92static struct sockaddr_un sunaddr;
93static int admin_process __P((int, char *));
94static int admin_reply __P((int, struct admin_com *, vchar_t *));
95
96int
97admin_handler()
98{
99	int so2;
100	struct sockaddr_storage from;
101	int fromlen = sizeof(from);
102	struct admin_com com;
103	char *combuf = NULL;
104	pid_t pid = -1;
105	int len, error = -1;
106
107	so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen);
108	if (so2 < 0) {
109		plog(LLV_ERROR, LOCATION, NULL,
110			"failed to accept admin command: %s\n",
111			strerror(errno));
112		return -1;
113	}
114
115	/* get buffer length */
116	while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) {
117		if (errno == EINTR)
118			continue;
119		plog(LLV_ERROR, LOCATION, NULL,
120			"failed to recv admin command: %s\n",
121			strerror(errno));
122		goto end;
123	}
124
125	/* sanity check */
126	if (len < sizeof(com)) {
127		plog(LLV_ERROR, LOCATION, NULL,
128			"invalid header length of admin command\n");
129		goto end;
130	}
131
132	/* get buffer to receive */
133	if ((combuf = racoon_malloc(com.ac_len)) == 0) {
134		plog(LLV_ERROR, LOCATION, NULL,
135			"failed to alloc buffer for admin command\n");
136		goto end;
137	}
138
139	/* get real data */
140	while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) {
141		if (errno == EINTR)
142			continue;
143		plog(LLV_ERROR, LOCATION, NULL,
144			"failed to recv admin command: %s\n",
145			strerror(errno));
146		goto end;
147	}
148
149	if (com.ac_cmd == ADMIN_RELOAD_CONF) {
150		/* reload does not work at all! */
151		signal_handler(SIGHUP);
152		goto end;
153	}
154
155	error = admin_process(so2, combuf);
156
157    end:
158	(void)close(so2);
159	if (combuf)
160		racoon_free(combuf);
161
162	/* exit if child's process. */
163	if (pid == 0 && !f_foreground)
164		exit(error);
165
166	return error;
167}
168
169/*
170 * main child's process.
171 */
172static int
173admin_process(so2, combuf)
174	int so2;
175	char *combuf;
176{
177	struct admin_com *com = (struct admin_com *)combuf;
178	vchar_t *buf = NULL;
179	vchar_t *id = NULL;
180	vchar_t *key = NULL;
181	int idtype = 0;
182	int error = 0;
183
184	com->ac_errno = 0;
185
186	switch (com->ac_cmd) {
187	case ADMIN_RELOAD_CONF:
188		/* don't entered because of proccessing it in other place. */
189		plog(LLV_ERROR, LOCATION, NULL, "should never reach here\n");
190		goto bad;
191
192	case ADMIN_SHOW_SCHED:
193	{
194		caddr_t p;
195		int len;
196		if (sched_dump(&p, &len) == -1)
197			com->ac_errno = -1;
198		buf = vmalloc(len);
199		if (buf == NULL)
200			com->ac_errno = -1;
201		else
202			memcpy(buf->v, p, len);
203	}
204		break;
205
206	case ADMIN_SHOW_EVT:
207		/* It's not really an error, don't force racoonctl to quit */
208		if ((buf = evt_dump()) == NULL)
209			com->ac_errno = 0;
210		break;
211
212	case ADMIN_SHOW_SA:
213	case ADMIN_FLUSH_SA:
214	    {
215		switch (com->ac_proto) {
216		case ADMIN_PROTO_ISAKMP:
217			switch (com->ac_cmd) {
218			case ADMIN_SHOW_SA:
219				buf = dumpph1();
220				if (buf == NULL)
221					com->ac_errno = -1;
222				break;
223			case ADMIN_FLUSH_SA:
224				flushph1();
225				break;
226			}
227			break;
228		case ADMIN_PROTO_IPSEC:
229		case ADMIN_PROTO_AH:
230		case ADMIN_PROTO_ESP:
231			switch (com->ac_cmd) {
232			case ADMIN_SHOW_SA:
233			    {
234				u_int p;
235				p = admin2pfkey_proto(com->ac_proto);
236				if (p == -1)
237					goto bad;
238				buf = pfkey_dump_sadb(p);
239				if (buf == NULL)
240					com->ac_errno = -1;
241			    }
242				break;
243			case ADMIN_FLUSH_SA:
244				pfkey_flush_sadb(com->ac_proto);
245				break;
246			}
247			break;
248
249		case ADMIN_PROTO_INTERNAL:
250			switch (com->ac_cmd) {
251			case ADMIN_SHOW_SA:
252				buf = NULL; /*XXX dumpph2(&error);*/
253				if (buf == NULL)
254					com->ac_errno = error;
255				break;
256			case ADMIN_FLUSH_SA:
257				/*XXX flushph2();*/
258				com->ac_errno = 0;
259				break;
260			}
261			break;
262
263		default:
264			/* ignore */
265			com->ac_errno = -1;
266		}
267	    }
268		break;
269
270	case ADMIN_DELETE_SA: {
271		struct ph1handle *iph1;
272		struct sockaddr *dst;
273		struct sockaddr *src;
274		char *loc, *rem;
275
276		src = (struct sockaddr *)
277			&((struct admin_com_indexes *)
278			    ((caddr_t)com + sizeof(*com)))->src;
279		dst = (struct sockaddr *)
280			&((struct admin_com_indexes *)
281			    ((caddr_t)com + sizeof(*com)))->dst;
282
283		if ((loc = strdup(saddrwop2str(src))) == NULL) {
284			plog(LLV_ERROR, LOCATION, NULL,
285			    "cannot allocate memory\n");
286			break;
287		}
288		if ((rem = strdup(saddrwop2str(dst))) == NULL) {
289			plog(LLV_ERROR, LOCATION, NULL,
290			    "cannot allocate memory\n");
291			break;
292		}
293
294		if ((iph1 = getph1byaddrwop(src, dst)) == NULL) {
295			plog(LLV_ERROR, LOCATION, NULL,
296			    "phase 1 for %s -> %s not found\n", loc, rem);
297		} else {
298			if (iph1->status == PHASE1ST_ESTABLISHED)
299				isakmp_info_send_d1(iph1);
300			purge_remote(iph1);
301		}
302
303		racoon_free(loc);
304		racoon_free(rem);
305
306		break;
307	}
308
309	case ADMIN_DELETE_ALL_SA_DST: {
310		struct ph1handle *iph1;
311		struct sockaddr *dst;
312		char *loc, *rem;
313
314		dst = (struct sockaddr *)
315			&((struct admin_com_indexes *)
316			    ((caddr_t)com + sizeof(*com)))->dst;
317
318		if ((rem = strdup(saddrwop2str(dst))) == NULL) {
319			plog(LLV_ERROR, LOCATION, NULL,
320			    "cannot allocate memory\n");
321			break;
322		}
323
324		plog(LLV_INFO, LOCATION, NULL,
325		    "Flushing all SAs for peer %s\n", rem);
326
327		while ((iph1 = getph1bydstaddrwop(dst)) != NULL) {
328			if ((loc = strdup(saddrwop2str(iph1->local))) == NULL) {
329				plog(LLV_ERROR, LOCATION, NULL,
330				    "cannot allocate memory\n");
331				break;
332			}
333
334			if (iph1->status == PHASE1ST_ESTABLISHED)
335				isakmp_info_send_d1(iph1);
336			purge_remote(iph1);
337
338			racoon_free(loc);
339		}
340
341		racoon_free(rem);
342
343		break;
344	}
345
346	case ADMIN_ESTABLISH_SA_PSK: {
347		struct admin_com_psk *acp;
348		char *data;
349
350		com->ac_cmd = ADMIN_ESTABLISH_SA;
351
352		acp = (struct admin_com_psk *)
353		    ((char *)com + sizeof(*com) +
354		    sizeof(struct admin_com_indexes));
355
356		idtype = acp->id_type;
357
358		if ((id = vmalloc(acp->id_len)) == NULL) {
359			plog(LLV_ERROR, LOCATION, NULL,
360			    "cannot allocate memory: %s\n",
361			    strerror(errno));
362			break;
363		}
364		data = (char *)(acp + 1);
365		memcpy(id->v, data, id->l);
366
367		if ((key = vmalloc(acp->key_len)) == NULL) {
368			plog(LLV_ERROR, LOCATION, NULL,
369			    "cannot allocate memory: %s\n",
370			    strerror(errno));
371			vfree(id);
372			break;
373		}
374		data = (char *)(data + acp->id_len);
375		memcpy(key->v, data, key->l);
376	}
377	/* FALLTHROUGH */
378	case ADMIN_ESTABLISH_SA:
379	    {
380		struct sockaddr *dst;
381		struct sockaddr *src;
382		src = (struct sockaddr *)
383			&((struct admin_com_indexes *)
384			    ((caddr_t)com + sizeof(*com)))->src;
385		dst = (struct sockaddr *)
386			&((struct admin_com_indexes *)
387			    ((caddr_t)com + sizeof(*com)))->dst;
388
389		switch (com->ac_proto) {
390		case ADMIN_PROTO_ISAKMP:
391		    {
392			struct remoteconf *rmconf;
393			struct sockaddr *remote;
394			struct sockaddr *local;
395
396			/* search appropreate configuration */
397			rmconf = getrmconf(dst);
398			if (rmconf == NULL) {
399				plog(LLV_ERROR, LOCATION, NULL,
400					"no configuration found "
401					"for %s\n", saddrwop2str(dst));
402				com->ac_errno = -1;
403				break;
404			}
405
406			/* get remote IP address and port number. */
407			remote = dupsaddr(dst);
408			if (remote == NULL) {
409				com->ac_errno = -1;
410				break;
411			}
412			switch (remote->sa_family) {
413			case AF_INET:
414				((struct sockaddr_in *)remote)->sin_port =
415					((struct sockaddr_in *)rmconf->remote)->sin_port;
416				break;
417#ifdef INET6
418			case AF_INET6:
419				((struct sockaddr_in6 *)remote)->sin6_port =
420					((struct sockaddr_in6 *)rmconf->remote)->sin6_port;
421				break;
422#endif
423			default:
424				plog(LLV_ERROR, LOCATION, NULL,
425					"invalid family: %d\n",
426					remote->sa_family);
427				com->ac_errno = -1;
428				break;
429			}
430
431			/* get local address */
432			local = dupsaddr(src);
433			if (local == NULL) {
434				com->ac_errno = -1;
435				break;
436			}
437			switch (local->sa_family) {
438			case AF_INET:
439				((struct sockaddr_in *)local)->sin_port =
440					getmyaddrsport(local);
441				break;
442#ifdef INET6
443			case AF_INET6:
444				((struct sockaddr_in6 *)local)->sin6_port =
445					getmyaddrsport(local);
446				break;
447#endif
448			default:
449				plog(LLV_ERROR, LOCATION, NULL,
450					"invalid family: %d\n",
451					local->sa_family);
452				com->ac_errno = -1;
453				break;
454			}
455
456			/* Set the id and key */
457			if (id && key) {
458				if (rmconf->idv != NULL) {
459					vfree(rmconf->idv);
460					rmconf->idv = NULL;
461				}
462				if (rmconf->key != NULL) {
463					vfree(rmconf->key);
464					rmconf->key = NULL;
465				}
466
467				rmconf->idvtype = idtype;
468				rmconf->idv = id;
469				rmconf->key = key;
470			}
471
472			plog(LLV_INFO, LOCATION, NULL,
473				"accept a request to establish IKE-SA: "
474				"%s\n", saddrwop2str(remote));
475
476			/* begin ident mode */
477			if (isakmp_ph1begin_i(rmconf, remote, local) < 0) {
478				com->ac_errno = -1;
479				break;
480			}
481		    }
482			break;
483		case ADMIN_PROTO_AH:
484		case ADMIN_PROTO_ESP:
485			break;
486		default:
487			/* ignore */
488			com->ac_errno = -1;
489		}
490	    }
491		break;
492
493	default:
494		plog(LLV_ERROR, LOCATION, NULL,
495			"invalid command: %d\n", com->ac_cmd);
496		com->ac_errno = -1;
497	}
498
499	if (admin_reply(so2, com, buf) < 0)
500		goto bad;
501
502	if (buf != NULL)
503		vfree(buf);
504
505	return 0;
506
507    bad:
508	if (buf != NULL)
509		vfree(buf);
510	return -1;
511}
512
513static int
514admin_reply(so, combuf, buf)
515	int so;
516	struct admin_com *combuf;
517	vchar_t *buf;
518{
519	int tlen;
520	char *retbuf = NULL;
521
522	if (buf != NULL)
523		tlen = sizeof(*combuf) + buf->l;
524	else
525		tlen = sizeof(*combuf);
526
527	retbuf = racoon_calloc(1, tlen);
528	if (retbuf == NULL) {
529		plog(LLV_ERROR, LOCATION, NULL,
530			"failed to allocate admin buffer\n");
531		return -1;
532	}
533
534	memcpy(retbuf, combuf, sizeof(*combuf));
535	((struct admin_com *)retbuf)->ac_len = tlen;
536
537	if (buf != NULL)
538		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
539
540	tlen = send(so, retbuf, tlen, 0);
541	racoon_free(retbuf);
542	if (tlen < 0) {
543		plog(LLV_ERROR, LOCATION, NULL,
544			"failed to send admin command: %s\n",
545			strerror(errno));
546		return -1;
547	}
548
549	return 0;
550}
551
552/* ADMIN_PROTO -> SADB_SATYPE */
553int
554admin2pfkey_proto(proto)
555	u_int proto;
556{
557	switch (proto) {
558	case ADMIN_PROTO_IPSEC:
559		return SADB_SATYPE_UNSPEC;
560	case ADMIN_PROTO_AH:
561		return SADB_SATYPE_AH;
562	case ADMIN_PROTO_ESP:
563		return SADB_SATYPE_ESP;
564	default:
565		plog(LLV_ERROR, LOCATION, NULL,
566			"unsupported proto for admin: %d\n", proto);
567		return -1;
568	}
569	/*NOTREACHED*/
570}
571
572int
573admin_init()
574{
575	if (adminsock_path == NULL) {
576		lcconf->sock_admin = -1;
577		return 0;
578	}
579
580	memset(&sunaddr, 0, sizeof(sunaddr));
581	sunaddr.sun_family = AF_UNIX;
582	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
583		"%s", adminsock_path);
584
585	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
586	if (lcconf->sock_admin == -1) {
587		plog(LLV_ERROR, LOCATION, NULL,
588			"socket: %s\n", strerror(errno));
589		return -1;
590	}
591
592	unlink(sunaddr.sun_path);
593	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
594			sizeof(sunaddr)) != 0) {
595		plog(LLV_ERROR, LOCATION, NULL,
596			"bind(sockname:%s): %s\n",
597			sunaddr.sun_path, strerror(errno));
598		(void)close(lcconf->sock_admin);
599		return -1;
600	}
601
602	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
603		plog(LLV_ERROR, LOCATION, NULL,
604		    "chown(%s, %d, %d): %s\n",
605		    sunaddr.sun_path, adminsock_owner,
606		    adminsock_group, strerror(errno));
607		(void)close(lcconf->sock_admin);
608		return -1;
609	}
610
611	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
612		plog(LLV_ERROR, LOCATION, NULL,
613		    "chmod(%s, 0%03o): %s\n",
614		    sunaddr.sun_path, adminsock_mode, strerror(errno));
615		(void)close(lcconf->sock_admin);
616		return -1;
617	}
618
619	if (listen(lcconf->sock_admin, 5) != 0) {
620		plog(LLV_ERROR, LOCATION, NULL,
621			"listen(sockname:%s): %s\n",
622			sunaddr.sun_path, strerror(errno));
623		(void)close(lcconf->sock_admin);
624		return -1;
625	}
626	plog(LLV_DEBUG, LOCATION, NULL,
627		"open %s as racoon management.\n", sunaddr.sun_path);
628
629	return 0;
630}
631
632int
633admin_close()
634{
635	close(lcconf->sock_admin);
636	return 0;
637}
638#endif
639