1/*	$KAME: admin.c,v 1.23 2001/06/01 10:12:55 sakane Exp $	*/
2
3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/types.h>
33#include <sys/param.h>
34#include <sys/socket.h>
35#include <sys/signal.h>
36#include <sys/un.h>
37
38#include <net/pfkeyv2.h>
39
40#include <netinet/in.h>
41
42#include <stdlib.h>
43#include <stdio.h>
44#include <string.h>
45#include <errno.h>
46#include <netdb.h>
47#ifdef HAVE_UNISTD_H
48#include <unistd.h>
49#endif
50
51#include "var.h"
52#include "misc.h"
53#include "vmbuf.h"
54#include "plog.h"
55#include "sockmisc.h"
56#include "debug.h"
57
58#include "schedule.h"
59#include "localconf.h"
60#include "remoteconf.h"
61#include "grabmyaddr.h"
62#include "isakmp_var.h"
63#include "isakmp.h"
64#include "oakley.h"
65#include "handler.h"
66#include "pfkey.h"
67#include "admin.h"
68#include "admin_var.h"
69#include "session.h"
70#include "gcmalloc.h"
71
72static struct sockaddr_un sunaddr;
73static int admin_process __P((int, char *));
74static int admin_reply __P((int, struct admin_com *, vchar_t *));
75
76int
77admin_handler()
78{
79	int so2;
80	struct sockaddr_storage from;
81	int fromlen = sizeof(from);
82	struct admin_com com;
83	char *combuf = NULL;
84	pid_t pid = -1;
85	int len, error = -1;
86
87	so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen);
88	if (so2 < 0) {
89		plog(LLV_ERROR, LOCATION, NULL,
90			"failed to accept admin command: %s\n",
91			strerror(errno));
92		return -1;
93	}
94
95	/* get buffer length */
96	while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) {
97		if (errno == EINTR)
98			continue;
99		plog(LLV_ERROR, LOCATION, NULL,
100			"failed to recv admin command: %s\n",
101			strerror(errno));
102		goto end;
103	}
104
105	/* sanity check */
106	if (len < sizeof(com)) {
107		plog(LLV_ERROR, LOCATION, NULL,
108			"invalid header length of admin command\n");
109		goto end;
110	}
111
112	/* get buffer to receive */
113	if ((combuf = racoon_malloc(com.ac_len)) == 0) {
114		plog(LLV_ERROR, LOCATION, NULL,
115			"failed to alloc buffer for admin command\n");
116		goto end;
117	}
118
119	/* get real data */
120	while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) {
121		if (errno == EINTR)
122			continue;
123		plog(LLV_ERROR, LOCATION, NULL,
124			"failed to recv admin command: %s\n",
125			strerror(errno));
126		goto end;
127	}
128
129	/* don't fork() because of reloading config. */
130	if (com.ac_cmd == ADMIN_RELOAD_CONF) {
131		/* reload does not work at all! */
132		signal_handler(SIGHUP);
133		goto end;
134	}
135
136	/* fork for processing */
137	if (!f_foreground) {
138		if ((pid = fork()) < 0) {
139			plog(LLV_ERROR, LOCATION, NULL,
140				"failed to fork for admin processing: %s\n",
141				strerror(errno));
142			goto end;
143		}
144
145		/* parant's process. */
146		if (pid != 0) {
147			error = 0;
148			goto end;
149		}
150
151		/* child's process */
152		admin_close();
153	}
154
155	/* exit in this function. */
156	error = admin_process(so2, combuf);
157
158    end:
159	(void)close(so2);
160	if (combuf)
161		racoon_free(combuf);
162
163	/* exit if child's process. */
164	if (pid == 0 && !f_foreground)
165		exit(error);
166
167	return error;
168}
169
170/*
171 * main child's process.
172 */
173static int
174admin_process(so2, combuf)
175	int so2;
176	char *combuf;
177{
178	struct admin_com *com = (struct admin_com *)combuf;
179	vchar_t *buf = NULL;
180	int error = 0;
181
182	com->ac_errno = 0;
183
184	switch (com->ac_cmd) {
185	case ADMIN_RELOAD_CONF:
186		/* don't entered because of proccessing it in other place. */
187		plog(LLV_ERROR, LOCATION, NULL, "should never reach here\n");
188		goto bad;
189
190	case ADMIN_SHOW_SCHED:
191	{
192		caddr_t p;
193		int len;
194		if (sched_dump(&p, &len) == -1)
195			com->ac_errno = -1;
196		buf = vmalloc(len);
197		if (buf == NULL)
198			com->ac_errno = -1;
199		memcpy(buf->v, p, len);
200	}
201		break;
202	case ADMIN_SHOW_SA:
203	case ADMIN_FLUSH_SA:
204	    {
205		switch (com->ac_proto) {
206		case ADMIN_PROTO_ISAKMP:
207			switch (com->ac_cmd) {
208			case ADMIN_SHOW_SA:
209				buf = dumpph1();
210				if (buf == NULL)
211					com->ac_errno = -1;
212				break;
213			case ADMIN_FLUSH_SA:
214				flushph1();
215				break;
216			}
217			break;
218		case ADMIN_PROTO_IPSEC:
219		case ADMIN_PROTO_AH:
220		case ADMIN_PROTO_ESP:
221			switch (com->ac_cmd) {
222			case ADMIN_SHOW_SA:
223			    {
224				u_int p;
225				p = admin2pfkey_proto(com->ac_proto);
226				if (p == -1)
227					goto bad;
228				buf = pfkey_dump_sadb(p);
229				if (buf == NULL)
230					com->ac_errno = -1;
231			    }
232				break;
233			case ADMIN_FLUSH_SA:
234				pfkey_flush_sadb(com->ac_proto);
235				break;
236			}
237			break;
238
239		case ADMIN_PROTO_INTERNAL:
240			switch (com->ac_cmd) {
241			case ADMIN_SHOW_SA:
242				buf = NULL;
243				if (buf == NULL)
244					com->ac_errno = error;
245				break;
246			case ADMIN_FLUSH_SA:
247				com->ac_errno = 0;
248				break;
249			}
250			break;
251
252		default:
253			/* ignore */
254			com->ac_errno = -1;
255		}
256	    }
257		break;
258
259	case ADMIN_DELETE_SA:
260		break;
261
262	case ADMIN_ESTABLISH_SA:
263	    {
264		struct sockaddr *dst;
265		struct sockaddr *src;
266		src = (struct sockaddr *)
267			&((struct admin_com_indexes *)
268			    ((caddr_t)com + sizeof(*com)))->src;
269		dst = (struct sockaddr *)
270			&((struct admin_com_indexes *)
271			    ((caddr_t)com + sizeof(*com)))->dst;
272
273		switch (com->ac_proto) {
274		case ADMIN_PROTO_ISAKMP:
275		    {
276			struct remoteconf *rmconf;
277			struct sockaddr *remote;
278			struct sockaddr *local;
279
280			/* search appropreate configuration */
281			rmconf = getrmconf(dst);
282			if (rmconf == NULL) {
283				plog(LLV_ERROR, LOCATION, NULL,
284					"no configuration found "
285					"for %s\n", saddrwop2str(dst));
286				com->ac_errno = -1;
287				break;
288			}
289
290			/* get remote IP address and port number. */
291			remote = dupsaddr(dst);
292			if (remote == NULL) {
293				com->ac_errno = -1;
294				break;
295			}
296			switch (remote->sa_family) {
297			case AF_INET:
298				((struct sockaddr_in *)remote)->sin_port =
299					((struct sockaddr_in *)rmconf->remote)->sin_port;
300				break;
301#ifdef INET6
302			case AF_INET6:
303				((struct sockaddr_in6 *)remote)->sin6_port =
304					((struct sockaddr_in6 *)rmconf->remote)->sin6_port;
305				break;
306#endif
307			default:
308				plog(LLV_ERROR, LOCATION, NULL,
309					"invalid family: %d\n",
310					remote->sa_family);
311				com->ac_errno = -1;
312				break;
313			}
314
315			/* get local address */
316			local = dupsaddr(src);
317			if (local == NULL) {
318				com->ac_errno = -1;
319				break;
320			}
321			switch (local->sa_family) {
322			case AF_INET:
323				((struct sockaddr_in *)local)->sin_port =
324					getmyaddrsport(local);
325				break;
326#ifdef INET6
327			case AF_INET6:
328				((struct sockaddr_in6 *)local)->sin6_port =
329					getmyaddrsport(local);
330				break;
331#endif
332			default:
333				plog(LLV_ERROR, LOCATION, NULL,
334					"invalid family: %d\n",
335					local->sa_family);
336				com->ac_errno = -1;
337				break;
338			}
339
340
341			plog(LLV_INFO, LOCATION, NULL,
342				"accept a request to establish IKE-SA: "
343				"%s\n", saddrwop2str(remote));
344
345			/* begin ident mode */
346			if (isakmp_ph1begin_i(rmconf, remote) < 0) {
347				com->ac_errno = -1;
348				break;
349			}
350		    }
351			break;
352		case ADMIN_PROTO_AH:
353		case ADMIN_PROTO_ESP:
354			break;
355		default:
356			/* ignore */
357			com->ac_errno = -1;
358		}
359	    }
360		break;
361
362	default:
363		plog(LLV_ERROR, LOCATION, NULL,
364			"invalid command: %d\n", com->ac_cmd);
365		com->ac_errno = -1;
366	}
367
368	if (admin_reply(so2, com, buf) < 0)
369		goto bad;
370
371	if (buf != NULL)
372		vfree(buf);
373
374	return 0;
375
376    bad:
377	if (buf != NULL)
378		vfree(buf);
379	return -1;
380}
381
382static int
383admin_reply(so, combuf, buf)
384	int so;
385	struct admin_com *combuf;
386	vchar_t *buf;
387{
388	int tlen;
389	char *retbuf = NULL;
390
391	if (buf != NULL)
392		tlen = sizeof(*combuf) + buf->l;
393	else
394		tlen = sizeof(*combuf);
395
396	retbuf = racoon_calloc(1, tlen);
397	if (retbuf == NULL) {
398		plog(LLV_ERROR, LOCATION, NULL,
399			"failed to allocate admin buffer\n");
400		return -1;
401	}
402
403	memcpy(retbuf, combuf, sizeof(*combuf));
404	((struct admin_com *)retbuf)->ac_len = tlen;
405
406	if (buf != NULL)
407		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
408
409	tlen = send(so, retbuf, tlen, 0);
410	racoon_free(retbuf);
411	if (tlen < 0) {
412		plog(LLV_ERROR, LOCATION, NULL,
413			"failed to send admin command: %s\n",
414			strerror(errno));
415		return -1;
416	}
417
418	return 0;
419}
420
421/* ADMIN_PROTO -> SADB_SATYPE */
422int
423admin2pfkey_proto(proto)
424	u_int proto;
425{
426	switch (proto) {
427	case ADMIN_PROTO_IPSEC:
428		return SADB_SATYPE_UNSPEC;
429	case ADMIN_PROTO_AH:
430		return SADB_SATYPE_AH;
431	case ADMIN_PROTO_ESP:
432		return SADB_SATYPE_ESP;
433	default:
434		plog(LLV_ERROR, LOCATION, NULL,
435			"unsupported proto for admin: %d\n", proto);
436		return -1;
437	}
438	/*NOTREACHED*/
439}
440
441int
442admin_init()
443{
444	memset(&sunaddr, 0, sizeof(sunaddr));
445	sunaddr.sun_family = AF_UNIX;
446	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
447		"%s", PORT_ADMIN);
448
449	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
450	if (lcconf->sock_admin < 0) {
451		plog(LLV_ERROR, LOCATION, NULL,
452			"socket: %s\n", strerror(errno));
453		return -1;
454	}
455
456	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
457			sizeof(sunaddr)) < 0) {
458		plog(LLV_ERROR, LOCATION, NULL,
459			"bind(sockname:%s): %s\n",
460			sunaddr.sun_path, strerror(errno));
461		(void)close(lcconf->sock_admin);
462		return -1;
463	}
464
465	if (listen(lcconf->sock_admin, 5) < 0) {
466		plog(LLV_ERROR, LOCATION, NULL,
467			"listen(sockname:%s): %s\n",
468			sunaddr.sun_path, strerror(errno));
469		(void)close(lcconf->sock_admin);
470		return -1;
471	}
472	plog(LLV_DEBUG, LOCATION, NULL,
473		"open %s as racoon management.\n", sunaddr.sun_path);
474
475	return 0;
476}
477
478int
479admin_close()
480{
481	close(lcconf->sock_admin);
482	unlink(sunaddr.sun_path);
483	return 0;
484}
485