admin.c revision 1.15
1/*	$NetBSD: admin.c,v 1.15 2006/10/02 21:19:43 manu Exp $	*/
2
3/* Id: admin.c,v 1.25 2006/04/06 14:31:04 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#ifdef ENABLE_HYBRID
62#include <resolv.h>
63#endif
64
65#include "var.h"
66#include "misc.h"
67#include "vmbuf.h"
68#include "plog.h"
69#include "sockmisc.h"
70#include "debug.h"
71
72#include "schedule.h"
73#include "localconf.h"
74#include "remoteconf.h"
75#include "grabmyaddr.h"
76#include "isakmp_var.h"
77#include "isakmp.h"
78#include "oakley.h"
79#include "handler.h"
80#include "evt.h"
81#include "pfkey.h"
82#include "ipsec_doi.h"
83#include "admin.h"
84#include "admin_var.h"
85#include "isakmp_inf.h"
86#ifdef ENABLE_HYBRID
87#include "isakmp_cfg.h"
88#endif
89#include "session.h"
90#include "gcmalloc.h"
91
92#ifdef ENABLE_ADMINPORT
93char *adminsock_path = ADMINSOCK_PATH;
94uid_t adminsock_owner = 0;
95gid_t adminsock_group = 0;
96mode_t adminsock_mode = 0600;
97
98static struct sockaddr_un sunaddr;
99static int admin_process __P((int, char *));
100static int admin_reply __P((int, struct admin_com *, vchar_t *));
101
102int
103admin_handler()
104{
105	int so2;
106	struct sockaddr_storage from;
107	socklen_t fromlen = sizeof(from);
108	struct admin_com com;
109	char *combuf = NULL;
110	int len, error = -1;
111
112	so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen);
113	if (so2 < 0) {
114		plog(LLV_ERROR, LOCATION, NULL,
115			"failed to accept admin command: %s\n",
116			strerror(errno));
117		return -1;
118	}
119
120	/* get buffer length */
121	while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) {
122		if (errno == EINTR)
123			continue;
124		plog(LLV_ERROR, LOCATION, NULL,
125			"failed to recv admin command: %s\n",
126			strerror(errno));
127		goto end;
128	}
129
130	/* sanity check */
131	if (len < sizeof(com)) {
132		plog(LLV_ERROR, LOCATION, NULL,
133			"invalid header length of admin command\n");
134		goto end;
135	}
136
137	/* get buffer to receive */
138	if ((combuf = racoon_malloc(com.ac_len)) == 0) {
139		plog(LLV_ERROR, LOCATION, NULL,
140			"failed to alloc buffer for admin command\n");
141		goto end;
142	}
143
144	/* get real data */
145	while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) {
146		if (errno == EINTR)
147			continue;
148		plog(LLV_ERROR, LOCATION, NULL,
149			"failed to recv admin command: %s\n",
150			strerror(errno));
151		goto end;
152	}
153
154	if (com.ac_cmd == ADMIN_RELOAD_CONF) {
155		/* reload does not work at all! */
156		signal_handler(SIGHUP);
157		goto end;
158	}
159
160	error = admin_process(so2, combuf);
161
162    end:
163	(void)close(so2);
164	if (combuf)
165		racoon_free(combuf);
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	vchar_t *id = NULL;
181	vchar_t *key = NULL;
182	int idtype = 0;
183	int error = -1;
184
185	com->ac_errno = 0;
186
187	switch (com->ac_cmd) {
188	case ADMIN_RELOAD_CONF:
189		/* don't entered because of proccessing it in other place. */
190		plog(LLV_ERROR, LOCATION, NULL, "should never reach here\n");
191		goto out;
192
193	case ADMIN_SHOW_SCHED:
194	{
195		caddr_t p;
196		int len;
197		if (sched_dump(&p, &len) == -1) {
198			com->ac_errno = -1;
199			break;
200		}
201
202		buf = vmalloc(len);
203		if (buf == NULL) {
204			com->ac_errno = -1;
205			break;
206		}
207
208		memcpy(buf->v, p, len);
209		racoon_free(p);
210	}
211		break;
212
213	case ADMIN_SHOW_EVT:
214		/* It's not really an error, don't force racoonctl to quit */
215		if ((buf = evt_dump()) == NULL)
216			com->ac_errno = 0;
217		break;
218
219	case ADMIN_SHOW_SA:
220	case ADMIN_FLUSH_SA:
221	    {
222		switch (com->ac_proto) {
223		case ADMIN_PROTO_ISAKMP:
224			switch (com->ac_cmd) {
225			case ADMIN_SHOW_SA:
226				buf = dumpph1();
227				if (buf == NULL)
228					com->ac_errno = -1;
229				break;
230			case ADMIN_FLUSH_SA:
231				flushph1();
232				break;
233			}
234			break;
235		case ADMIN_PROTO_IPSEC:
236		case ADMIN_PROTO_AH:
237		case ADMIN_PROTO_ESP:
238			switch (com->ac_cmd) {
239			case ADMIN_SHOW_SA:
240			    {
241				u_int p;
242				p = admin2pfkey_proto(com->ac_proto);
243				if (p == -1)
244					goto out;
245				buf = pfkey_dump_sadb(p);
246				if (buf == NULL)
247					com->ac_errno = -1;
248			    }
249				break;
250			case ADMIN_FLUSH_SA:
251				pfkey_flush_sadb(com->ac_proto);
252				break;
253			}
254			break;
255
256		case ADMIN_PROTO_INTERNAL:
257			switch (com->ac_cmd) {
258			case ADMIN_SHOW_SA:
259				buf = NULL; /*XXX dumpph2(&error);*/
260				if (buf == NULL)
261					com->ac_errno = error;
262				break;
263			case ADMIN_FLUSH_SA:
264				/*XXX flushph2();*/
265				com->ac_errno = 0;
266				break;
267			}
268			break;
269
270		default:
271			/* ignore */
272			com->ac_errno = -1;
273		}
274	    }
275		break;
276
277	case ADMIN_DELETE_SA: {
278		struct ph1handle *iph1;
279		struct sockaddr *dst;
280		struct sockaddr *src;
281		char *loc, *rem;
282
283		src = (struct sockaddr *)
284			&((struct admin_com_indexes *)
285			    ((caddr_t)com + sizeof(*com)))->src;
286		dst = (struct sockaddr *)
287			&((struct admin_com_indexes *)
288			    ((caddr_t)com + sizeof(*com)))->dst;
289
290		loc = racoon_strdup(saddrwop2str(src));
291		rem = racoon_strdup(saddrwop2str(dst));
292		STRDUP_FATAL(loc);
293		STRDUP_FATAL(rem);
294
295		if ((iph1 = getph1byaddrwop(src, dst)) == NULL) {
296			plog(LLV_ERROR, LOCATION, NULL,
297			    "phase 1 for %s -> %s not found\n", loc, rem);
298		} else {
299			if (iph1->status == PHASE1ST_ESTABLISHED)
300				isakmp_info_send_d1(iph1);
301			purge_remote(iph1);
302		}
303
304		racoon_free(loc);
305		racoon_free(rem);
306
307		break;
308	}
309
310#ifdef ENABLE_HYBRID
311	case ADMIN_LOGOUT_USER: {
312		struct ph1handle *iph1;
313		char *user;
314		int found = 0;
315
316		if (com->ac_len > sizeof(com) + LOGINLEN + 1) {
317			plog(LLV_ERROR, LOCATION, NULL,
318			    "malformed message (login too long)\n");
319			break;
320		}
321
322		user = (char *)(com + 1);
323		found = purgeph1bylogin(user);
324		plog(LLV_INFO, LOCATION, NULL,
325		    "deleted %d SA for user \"%s\"\n", found, user);
326
327		break;
328	}
329#endif
330
331	case ADMIN_DELETE_ALL_SA_DST: {
332		struct ph1handle *iph1;
333		struct sockaddr *dst;
334		char *loc, *rem;
335
336		dst = (struct sockaddr *)
337			&((struct admin_com_indexes *)
338			    ((caddr_t)com + sizeof(*com)))->dst;
339
340		rem = racoon_strdup(saddrwop2str(dst));
341		STRDUP_FATAL(rem);
342
343		plog(LLV_INFO, LOCATION, NULL,
344		    "Flushing all SAs for peer %s\n", rem);
345
346		while ((iph1 = getph1bydstaddrwop(dst)) != NULL) {
347			loc = racoon_strdup(saddrwop2str(iph1->local));
348			STRDUP_FATAL(loc);
349
350			if (iph1->status == PHASE1ST_ESTABLISHED)
351				isakmp_info_send_d1(iph1);
352			purge_remote(iph1);
353
354			racoon_free(loc);
355		}
356
357		racoon_free(rem);
358
359		break;
360	}
361
362	case ADMIN_ESTABLISH_SA_PSK: {
363		struct admin_com_psk *acp;
364		char *data;
365
366		com->ac_cmd = ADMIN_ESTABLISH_SA;
367
368		acp = (struct admin_com_psk *)
369		    ((char *)com + sizeof(*com) +
370		    sizeof(struct admin_com_indexes));
371
372		idtype = acp->id_type;
373
374		if ((id = vmalloc(acp->id_len)) == NULL) {
375			plog(LLV_ERROR, LOCATION, NULL,
376			    "cannot allocate memory: %s\n",
377			    strerror(errno));
378			break;
379		}
380		data = (char *)(acp + 1);
381		memcpy(id->v, data, id->l);
382
383		if ((key = vmalloc(acp->key_len)) == NULL) {
384			plog(LLV_ERROR, LOCATION, NULL,
385			    "cannot allocate memory: %s\n",
386			    strerror(errno));
387			vfree(id);
388			id = NULL;
389			break;
390		}
391		data = (char *)(data + acp->id_len);
392		memcpy(key->v, data, key->l);
393	}
394	/* FALLTHROUGH */
395	case ADMIN_ESTABLISH_SA:
396	    {
397		struct sockaddr *dst;
398		struct sockaddr *src;
399		src = (struct sockaddr *)
400			&((struct admin_com_indexes *)
401			    ((caddr_t)com + sizeof(*com)))->src;
402		dst = (struct sockaddr *)
403			&((struct admin_com_indexes *)
404			    ((caddr_t)com + sizeof(*com)))->dst;
405
406		switch (com->ac_proto) {
407		case ADMIN_PROTO_ISAKMP: {
408			struct remoteconf *rmconf;
409			struct sockaddr *remote = NULL;
410			struct sockaddr *local = NULL;
411			u_int16_t port;
412
413			com->ac_errno = -1;
414
415			/* search appropreate configuration */
416			rmconf = getrmconf(dst);
417			if (rmconf == NULL) {
418				plog(LLV_ERROR, LOCATION, NULL,
419					"no configuration found "
420					"for %s\n", saddrwop2str(dst));
421				goto out1;
422			}
423
424			/* get remote IP address and port number. */
425			if ((remote = dupsaddr(dst)) == NULL)
426				goto out1;
427
428			port = extract_port(rmconf->remote);
429			if (set_port(remote, port) == NULL)
430				goto out1;
431
432			/* get local address */
433			if ((local = dupsaddr(src)) == NULL)
434				goto out1;
435
436			if (set_port(local, getmyaddrsport(local)) == NULL)
437				goto out1;
438
439#ifdef ENABLE_HYBRID
440			/* Set the id and key */
441			if (id && key) {
442				if (xauth_rmconf_used(&rmconf->xauth) == -1)
443					goto out1;
444
445				if (rmconf->xauth->login != NULL) {
446					vfree(rmconf->xauth->login);
447					rmconf->xauth->login = NULL;
448				}
449				if (rmconf->xauth->pass != NULL) {
450					vfree(rmconf->xauth->pass);
451					rmconf->xauth->pass = NULL;
452				}
453
454				rmconf->xauth->login = id;
455				rmconf->xauth->pass = key;
456			}
457#endif
458
459			plog(LLV_INFO, LOCATION, NULL,
460				"accept a request to establish IKE-SA: "
461				"%s\n", saddrwop2str(remote));
462
463			/* begin ident mode */
464			if (isakmp_ph1begin_i(rmconf, remote, local) < 0)
465				goto out1;
466
467			com->ac_errno = 0;
468out1:
469			if (local != NULL)
470				racoon_free(local);
471			if (remote != NULL)
472				racoon_free(remote);
473			break;
474		}
475		case ADMIN_PROTO_AH:
476		case ADMIN_PROTO_ESP:
477			break;
478		default:
479			/* ignore */
480			com->ac_errno = -1;
481		}
482	    }
483		break;
484
485	default:
486		plog(LLV_ERROR, LOCATION, NULL,
487			"invalid command: %d\n", com->ac_cmd);
488		com->ac_errno = -1;
489	}
490
491	if ((error = admin_reply(so2, com, buf)) != 0)
492		goto out;
493
494	error = 0;
495out:
496	if (buf != NULL)
497		vfree(buf);
498
499	return error;
500}
501
502static int
503admin_reply(so, combuf, buf)
504	int so;
505	struct admin_com *combuf;
506	vchar_t *buf;
507{
508	int tlen;
509	char *retbuf = NULL;
510
511	if (buf != NULL)
512		tlen = sizeof(*combuf) + buf->l;
513	else
514		tlen = sizeof(*combuf);
515
516	retbuf = racoon_calloc(1, tlen);
517	if (retbuf == NULL) {
518		plog(LLV_ERROR, LOCATION, NULL,
519			"failed to allocate admin buffer\n");
520		return -1;
521	}
522
523	memcpy(retbuf, combuf, sizeof(*combuf));
524	((struct admin_com *)retbuf)->ac_len = tlen;
525
526	if (buf != NULL)
527		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
528
529	tlen = send(so, retbuf, tlen, 0);
530	racoon_free(retbuf);
531	if (tlen < 0) {
532		plog(LLV_ERROR, LOCATION, NULL,
533			"failed to send admin command: %s\n",
534			strerror(errno));
535		return -1;
536	}
537
538	return 0;
539}
540
541/* ADMIN_PROTO -> SADB_SATYPE */
542int
543admin2pfkey_proto(proto)
544	u_int proto;
545{
546	switch (proto) {
547	case ADMIN_PROTO_IPSEC:
548		return SADB_SATYPE_UNSPEC;
549	case ADMIN_PROTO_AH:
550		return SADB_SATYPE_AH;
551	case ADMIN_PROTO_ESP:
552		return SADB_SATYPE_ESP;
553	default:
554		plog(LLV_ERROR, LOCATION, NULL,
555			"unsupported proto for admin: %d\n", proto);
556		return -1;
557	}
558	/*NOTREACHED*/
559}
560
561int
562admin_init()
563{
564	if (adminsock_path == NULL) {
565		lcconf->sock_admin = -1;
566		return 0;
567	}
568
569	memset(&sunaddr, 0, sizeof(sunaddr));
570	sunaddr.sun_family = AF_UNIX;
571	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
572		"%s", adminsock_path);
573
574	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
575	if (lcconf->sock_admin == -1) {
576		plog(LLV_ERROR, LOCATION, NULL,
577			"socket: %s\n", strerror(errno));
578		return -1;
579	}
580
581	unlink(sunaddr.sun_path);
582	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
583			sizeof(sunaddr)) != 0) {
584		plog(LLV_ERROR, LOCATION, NULL,
585			"bind(sockname:%s): %s\n",
586			sunaddr.sun_path, strerror(errno));
587		(void)close(lcconf->sock_admin);
588		return -1;
589	}
590
591	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
592		plog(LLV_ERROR, LOCATION, NULL,
593		    "chown(%s, %d, %d): %s\n",
594		    sunaddr.sun_path, adminsock_owner,
595		    adminsock_group, strerror(errno));
596		(void)close(lcconf->sock_admin);
597		return -1;
598	}
599
600	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
601		plog(LLV_ERROR, LOCATION, NULL,
602		    "chmod(%s, 0%03o): %s\n",
603		    sunaddr.sun_path, adminsock_mode, strerror(errno));
604		(void)close(lcconf->sock_admin);
605		return -1;
606	}
607
608	if (listen(lcconf->sock_admin, 5) != 0) {
609		plog(LLV_ERROR, LOCATION, NULL,
610			"listen(sockname:%s): %s\n",
611			sunaddr.sun_path, strerror(errno));
612		(void)close(lcconf->sock_admin);
613		return -1;
614	}
615	plog(LLV_DEBUG, LOCATION, NULL,
616		"open %s as racoon management.\n", sunaddr.sun_path);
617
618	return 0;
619}
620
621int
622admin_close()
623{
624	close(lcconf->sock_admin);
625	return 0;
626}
627#endif
628
629