admin.c revision 1.18.8.1
1/*	$NetBSD: admin.c,v 1.18.8.1 2008/03/24 07:14:29 keiichi 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#include PATH_IPSEC_H
47
48
49#include <stdlib.h>
50#include <stdio.h>
51#include <string.h>
52#include <errno.h>
53#include <netdb.h>
54#ifdef HAVE_UNISTD_H
55#include <unistd.h>
56#endif
57#ifdef ENABLE_HYBRID
58#include <resolv.h>
59#endif
60
61#include "var.h"
62#include "misc.h"
63#include "vmbuf.h"
64#include "plog.h"
65#include "sockmisc.h"
66#include "debug.h"
67
68#include "schedule.h"
69#include "localconf.h"
70#include "remoteconf.h"
71#include "grabmyaddr.h"
72#include "isakmp_var.h"
73#include "isakmp.h"
74#include "oakley.h"
75#include "handler.h"
76#include "evt.h"
77#include "pfkey.h"
78#include "ipsec_doi.h"
79#include "policy.h"
80#include "admin.h"
81#include "admin_var.h"
82#include "isakmp_inf.h"
83#ifdef ENABLE_HYBRID
84#include "isakmp_cfg.h"
85#endif
86#include "session.h"
87#include "gcmalloc.h"
88
89#ifdef ENABLE_ADMINPORT
90char *adminsock_path = ADMINSOCK_PATH;
91uid_t adminsock_owner = 0;
92gid_t adminsock_group = 0;
93mode_t adminsock_mode = 0600;
94
95static struct sockaddr_un sunaddr;
96static int admin_process __P((int, char *));
97static int admin_reply __P((int, struct admin_com *, int, vchar_t *));
98
99int
100admin_handler()
101{
102	int so2;
103	struct sockaddr_storage from;
104	socklen_t fromlen = sizeof(from);
105	struct admin_com com;
106	char *combuf = NULL;
107	int len, error = -1;
108
109	so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen);
110	if (so2 < 0) {
111		plog(LLV_ERROR, LOCATION, NULL,
112			"failed to accept admin command: %s\n",
113			strerror(errno));
114		return -1;
115	}
116
117	/* get buffer length */
118	while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) {
119		if (errno == EINTR)
120			continue;
121		plog(LLV_ERROR, LOCATION, NULL,
122			"failed to recv admin command: %s\n",
123			strerror(errno));
124		goto end;
125	}
126
127	/* sanity check */
128	if (len < sizeof(com)) {
129		plog(LLV_ERROR, LOCATION, NULL,
130			"invalid header length of admin command\n");
131		goto end;
132	}
133
134	/* get buffer to receive */
135	if ((combuf = racoon_malloc(com.ac_len)) == 0) {
136		plog(LLV_ERROR, LOCATION, NULL,
137			"failed to alloc buffer for admin command\n");
138		goto end;
139	}
140
141	/* get real data */
142	while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) {
143		if (errno == EINTR)
144			continue;
145		plog(LLV_ERROR, LOCATION, NULL,
146			"failed to recv admin command: %s\n",
147			strerror(errno));
148		goto end;
149	}
150
151	error = admin_process(so2, combuf);
152
153end:
154	if (error == -2) {
155		plog(LLV_DEBUG, LOCATION, NULL,
156			"[%d] admin connection established\n", so2);
157	} else {
158		(void)close(so2);
159	}
160
161	if (combuf)
162		racoon_free(combuf);
163
164	return error;
165}
166
167/*
168 * main child's process.
169 */
170static int
171admin_process(so2, combuf)
172	int so2;
173	char *combuf;
174{
175	struct admin_com *com = (struct admin_com *)combuf;
176	vchar_t *buf = NULL;
177	vchar_t *id = NULL;
178	vchar_t *key = NULL;
179	int idtype = 0;
180	int error = 0, ac_errno = 0;
181	struct evt_listener_list *event_list = NULL;
182
183	if (com->ac_cmd & ADMIN_FLAG_VERSION)
184		com->ac_cmd &= ~ADMIN_FLAG_VERSION;
185	else
186		com->ac_version = 0;
187
188	switch (com->ac_cmd) {
189	case ADMIN_RELOAD_CONF:
190		signal_handler(SIGHUP);
191		break;
192
193	case ADMIN_SHOW_SCHED: {
194		caddr_t p = NULL;
195		int len;
196
197		if (sched_dump(&p, &len) != -1) {
198			buf = vmalloc(len);
199			if (buf != NULL)
200				memcpy(buf->v, p, len);
201			else
202				ac_errno = ENOMEM;
203			racoon_free(p);
204		} else
205			ac_errno = ENOMEM;
206		break;
207	}
208
209	case ADMIN_SHOW_EVT:
210		if (com->ac_version == 0) {
211			buf = evt_dump();
212			ac_errno = 0;
213		}
214		break;
215
216	case ADMIN_SHOW_SA:
217	case ADMIN_FLUSH_SA:
218		switch (com->ac_proto) {
219		case ADMIN_PROTO_ISAKMP:
220			switch (com->ac_cmd) {
221			case ADMIN_SHOW_SA:
222				buf = dumpph1();
223				if (buf == NULL)
224					ac_errno = ENOMEM;
225				break;
226			case ADMIN_FLUSH_SA:
227				flushph1();
228				break;
229			default:
230				ac_errno = ENOTSUP;
231				break;
232			}
233			break;
234		case ADMIN_PROTO_IPSEC:
235		case ADMIN_PROTO_AH:
236		case ADMIN_PROTO_ESP:
237			switch (com->ac_cmd) {
238			case ADMIN_SHOW_SA: {
239				u_int p;
240				p = admin2pfkey_proto(com->ac_proto);
241				if (p != -1) {
242					buf = pfkey_dump_sadb(p);
243					if (buf == NULL)
244						ac_errno = ENOMEM;
245				} else
246					ac_errno = EINVAL;
247				break;
248			}
249			case ADMIN_FLUSH_SA:
250				pfkey_flush_sadb(com->ac_proto);
251				break;
252			default:
253				ac_errno = ENOTSUP;
254				break;
255			}
256			break;
257		case ADMIN_PROTO_INTERNAL:
258			switch (com->ac_cmd) {
259			case ADMIN_SHOW_SA:
260				buf = NULL; /*XXX dumpph2(&error);*/
261				ac_errno = ENOTSUP;
262				break;
263			case ADMIN_FLUSH_SA:
264				/*XXX flushph2();*/
265				break;
266			default:
267				ac_errno = ENOTSUP;
268				break;
269			}
270			break;
271		default:
272			ac_errno = ENOTSUP;
273		}
274		break;
275
276	case ADMIN_DELETE_SA: {
277		struct ph1handle *iph1;
278		struct sockaddr *dst;
279		struct sockaddr *src;
280		char *loc, *rem;
281
282		src = (struct sockaddr *)
283			&((struct admin_com_indexes *)
284			    ((caddr_t)com + sizeof(*com)))->src;
285		dst = (struct sockaddr *)
286			&((struct admin_com_indexes *)
287			    ((caddr_t)com + sizeof(*com)))->dst;
288
289		loc = racoon_strdup(saddrwop2str(src));
290		rem = racoon_strdup(saddrwop2str(dst));
291		STRDUP_FATAL(loc);
292		STRDUP_FATAL(rem);
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		break;
306	}
307
308#ifdef ENABLE_HYBRID
309	case ADMIN_LOGOUT_USER: {
310		struct ph1handle *iph1;
311		char *user;
312		int found = 0;
313
314		if (com->ac_len > sizeof(com) + LOGINLEN + 1) {
315			plog(LLV_ERROR, LOCATION, NULL,
316			    "malformed message (login too long)\n");
317			break;
318		}
319
320		user = (char *)(com + 1);
321		found = purgeph1bylogin(user);
322		plog(LLV_INFO, LOCATION, NULL,
323		    "deleted %d SA for user \"%s\"\n", found, user);
324
325		break;
326	}
327#endif
328
329	case ADMIN_DELETE_ALL_SA_DST: {
330		struct ph1handle *iph1;
331		struct sockaddr *dst;
332		char *loc, *rem;
333
334		dst = (struct sockaddr *)
335			&((struct admin_com_indexes *)
336			    ((caddr_t)com + sizeof(*com)))->dst;
337
338		rem = racoon_strdup(saddrwop2str(dst));
339		STRDUP_FATAL(rem);
340
341		plog(LLV_INFO, LOCATION, NULL,
342		    "Flushing all SAs for peer %s\n", rem);
343
344		while ((iph1 = getph1bydstaddrwop(dst)) != NULL) {
345			loc = racoon_strdup(saddrwop2str(iph1->local));
346			STRDUP_FATAL(loc);
347
348			if (iph1->status == PHASE1ST_ESTABLISHED)
349				isakmp_info_send_d1(iph1);
350			purge_remote(iph1);
351
352			racoon_free(loc);
353		}
354
355		racoon_free(rem);
356		break;
357	}
358
359	case ADMIN_ESTABLISH_SA_PSK: {
360		struct admin_com_psk *acp;
361		char *data;
362
363		acp = (struct admin_com_psk *)
364		    ((char *)com + sizeof(*com) +
365		    sizeof(struct admin_com_indexes));
366
367		idtype = acp->id_type;
368
369		if ((id = vmalloc(acp->id_len)) == NULL) {
370			plog(LLV_ERROR, LOCATION, NULL,
371			    "cannot allocate memory: %s\n",
372			    strerror(errno));
373			break;
374		}
375		data = (char *)(acp + 1);
376		memcpy(id->v, data, id->l);
377
378		if ((key = vmalloc(acp->key_len)) == NULL) {
379			plog(LLV_ERROR, LOCATION, NULL,
380			    "cannot allocate memory: %s\n",
381			    strerror(errno));
382			vfree(id);
383			id = NULL;
384			break;
385		}
386		data = (char *)(data + acp->id_len);
387		memcpy(key->v, data, key->l);
388	}
389	/* FALLTHROUGH */
390	case ADMIN_ESTABLISH_SA: {
391		struct admin_com_indexes *ndx;
392		struct sockaddr *dst;
393		struct sockaddr *src;
394
395		ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com));
396		src = (struct sockaddr *) &ndx->src;
397		dst = (struct sockaddr *) &ndx->dst;
398
399		switch (com->ac_proto) {
400		case ADMIN_PROTO_ISAKMP: {
401			struct ph1handle *ph1;
402			struct remoteconf *rmconf;
403			struct sockaddr *remote = NULL;
404			struct sockaddr *local = NULL;
405			u_int16_t port;
406
407			ac_errno = -1;
408
409			/* connected already? */
410			ph1 = getph1byaddrwop(src, dst);
411			if (ph1 != NULL) {
412				event_list = &ph1->evt_listeners;
413				if (ph1->status == PHASE1ST_ESTABLISHED)
414					ac_errno = EEXIST;
415				else
416					ac_errno = 0;
417				break;
418			}
419
420			/* search appropreate configuration */
421			rmconf = getrmconf(dst);
422			if (rmconf == NULL) {
423				plog(LLV_ERROR, LOCATION, NULL,
424					"no configuration found "
425					"for %s\n", saddrwop2str(dst));
426				goto out1;
427			}
428
429			/* get remote IP address and port number. */
430			if ((remote = dupsaddr(dst)) == NULL)
431				goto out1;
432
433			port = extract_port(rmconf->remote);
434			if (set_port(remote, port) == NULL)
435				goto out1;
436
437			/* get local address */
438			if ((local = dupsaddr(src)) == NULL)
439				goto out1;
440
441			port = ntohs(getmyaddrsport(local));
442			if (set_port(local, port) == NULL)
443				goto out1;
444
445#ifdef ENABLE_HYBRID
446			/* Set the id and key */
447			if (id && key) {
448				if (xauth_rmconf_used(&rmconf->xauth) == -1)
449					goto out1;
450
451				if (rmconf->xauth->login != NULL) {
452					vfree(rmconf->xauth->login);
453					rmconf->xauth->login = NULL;
454				}
455				if (rmconf->xauth->pass != NULL) {
456					vfree(rmconf->xauth->pass);
457					rmconf->xauth->pass = NULL;
458				}
459
460				rmconf->xauth->login = id;
461				rmconf->xauth->pass = key;
462			}
463#endif
464
465			plog(LLV_INFO, LOCATION, NULL,
466				"accept a request to establish IKE-SA: "
467				"%s\n", saddrwop2str(remote));
468
469			/* begin ident mode */
470			ph1 = isakmp_ph1begin_i(rmconf, remote, local);
471			if (ph1 == NULL)
472				goto out1;
473
474			event_list = &ph1->evt_listeners;
475			ac_errno = 0;
476out1:
477			if (local != NULL)
478				racoon_free(local);
479			if (remote != NULL)
480				racoon_free(remote);
481			break;
482		}
483		case ADMIN_PROTO_AH:
484		case ADMIN_PROTO_ESP: {
485			struct ph2handle *iph2;
486			struct secpolicy *sp_out = NULL, *sp_in = NULL;
487			struct policyindex spidx;
488
489			ac_errno = -1;
490
491			/* got outbound policy */
492			memset(&spidx, 0, sizeof(spidx));
493			spidx.dir = IPSEC_DIR_OUTBOUND;
494			memcpy(&spidx.src, src, sizeof(spidx.src));
495			memcpy(&spidx.dst, dst, sizeof(spidx.dst));
496			spidx.prefs = ndx->prefs;
497			spidx.prefd = ndx->prefd;
498			spidx.ul_proto = ndx->ul_proto;
499
500			sp_out = getsp_r(&spidx);
501			if (sp_out) {
502				plog(LLV_DEBUG, LOCATION, NULL,
503					"suitable outbound SP found: %s.\n",
504					spidx2str(&sp_out->spidx));
505			} else {
506				ac_errno = ENOENT;
507				plog(LLV_NOTIFY, LOCATION, NULL,
508					"no outbound policy found: %s\n",
509					spidx2str(&spidx));
510				break;
511			}
512
513			iph2 = getph2byid(src, dst, sp_out->id);
514			if (iph2 != NULL) {
515				event_list = &iph2->evt_listeners;
516				if (iph2->status == PHASE2ST_ESTABLISHED)
517					ac_errno = EEXIST;
518				else
519					ac_errno = 0;
520				break;
521			}
522
523			/* get inbound policy */
524			memset(&spidx, 0, sizeof(spidx));
525			spidx.dir = IPSEC_DIR_INBOUND;
526			memcpy(&spidx.src, dst, sizeof(spidx.src));
527			memcpy(&spidx.dst, src, sizeof(spidx.dst));
528			spidx.prefs = ndx->prefd;
529			spidx.prefd = ndx->prefs;
530			spidx.ul_proto = ndx->ul_proto;
531
532			sp_in = getsp_r(&spidx);
533			if (sp_in) {
534				plog(LLV_DEBUG, LOCATION, NULL,
535					"suitable inbound SP found: %s.\n",
536					spidx2str(&sp_in->spidx));
537			} else {
538				ac_errno = ENOENT;
539				plog(LLV_NOTIFY, LOCATION, NULL,
540					"no inbound policy found: %s\n",
541				spidx2str(&spidx));
542				break;
543			}
544
545			/* allocate a phase 2 */
546			iph2 = newph2();
547			if (iph2 == NULL) {
548				plog(LLV_ERROR, LOCATION, NULL,
549					"failed to allocate phase2 entry.\n");
550				break;
551			}
552			iph2->side = INITIATOR;
553			iph2->satype = admin2pfkey_proto(com->ac_proto);
554			iph2->spid = sp_out->id;
555			iph2->seq = pk_getseq();
556			iph2->status = PHASE2ST_STATUS2;
557
558			/* set end addresses of SA */
559			iph2->dst = dupsaddr(dst);
560			iph2->src = dupsaddr(src);
561			if (iph2->dst == NULL || iph2->src == NULL) {
562				delph2(iph2);
563				break;
564			}
565
566			if (isakmp_get_sainfo(iph2, sp_out, sp_in) < 0) {
567				delph2(iph2);
568				break;
569			}
570
571			insph2(iph2);
572			if (isakmp_post_acquire(iph2) < 0) {
573				unbindph12(iph2);
574				remph2(iph2);
575				delph2(iph2);
576				break;
577			}
578
579			event_list = &iph2->evt_listeners;
580			ac_errno = 0;
581			break;
582		}
583		default:
584			/* ignore */
585			ac_errno = ENOTSUP;
586		}
587		break;
588	}
589
590	default:
591		plog(LLV_ERROR, LOCATION, NULL,
592			"invalid command: %d\n", com->ac_cmd);
593		ac_errno = ENOTSUP;
594	}
595
596	if ((error = admin_reply(so2, com, ac_errno, buf)) != 0)
597		goto out;
598
599	/* start pushing events if so requested */
600	if ((ac_errno == 0) &&
601	    (com->ac_version >= 1) &&
602	    (com->ac_cmd == ADMIN_SHOW_EVT || event_list != NULL))
603		error = evt_subscribe(event_list, so2);
604out:
605	if (buf != NULL)
606		vfree(buf);
607
608	return error;
609}
610
611static int
612admin_reply(so, req, ac_errno, buf)
613	int so, ac_errno;
614	struct admin_com *req;
615	vchar_t *buf;
616{
617	int tlen;
618	struct admin_com *combuf;
619	char *retbuf = NULL;
620
621	if (buf != NULL)
622		tlen = sizeof(*combuf) + buf->l;
623	else
624		tlen = sizeof(*combuf);
625
626	retbuf = racoon_calloc(1, tlen);
627	if (retbuf == NULL) {
628		plog(LLV_ERROR, LOCATION, NULL,
629			"failed to allocate admin buffer\n");
630		return -1;
631	}
632
633	combuf = (struct admin_com *) retbuf;
634	combuf->ac_len = tlen;
635	combuf->ac_cmd = req->ac_cmd & ~ADMIN_FLAG_VERSION;
636	combuf->ac_errno = ac_errno;
637	combuf->ac_proto = req->ac_proto;
638
639	if (buf != NULL)
640		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
641
642	tlen = send(so, retbuf, tlen, 0);
643	racoon_free(retbuf);
644	if (tlen < 0) {
645		plog(LLV_ERROR, LOCATION, NULL,
646			"failed to send admin command: %s\n",
647			strerror(errno));
648		return -1;
649	}
650
651	return 0;
652}
653
654/* ADMIN_PROTO -> SADB_SATYPE */
655int
656admin2pfkey_proto(proto)
657	u_int proto;
658{
659	switch (proto) {
660	case ADMIN_PROTO_IPSEC:
661		return SADB_SATYPE_UNSPEC;
662	case ADMIN_PROTO_AH:
663		return SADB_SATYPE_AH;
664	case ADMIN_PROTO_ESP:
665		return SADB_SATYPE_ESP;
666	default:
667		plog(LLV_ERROR, LOCATION, NULL,
668			"unsupported proto for admin: %d\n", proto);
669		return -1;
670	}
671	/*NOTREACHED*/
672}
673
674int
675admin_init()
676{
677	if (adminsock_path == NULL) {
678		lcconf->sock_admin = -1;
679		return 0;
680	}
681
682	memset(&sunaddr, 0, sizeof(sunaddr));
683	sunaddr.sun_family = AF_UNIX;
684	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
685		"%s", adminsock_path);
686
687	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
688	if (lcconf->sock_admin == -1) {
689		plog(LLV_ERROR, LOCATION, NULL,
690			"socket: %s\n", strerror(errno));
691		return -1;
692	}
693
694	unlink(sunaddr.sun_path);
695	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
696			sizeof(sunaddr)) != 0) {
697		plog(LLV_ERROR, LOCATION, NULL,
698			"bind(sockname:%s): %s\n",
699			sunaddr.sun_path, strerror(errno));
700		(void)close(lcconf->sock_admin);
701		return -1;
702	}
703
704	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
705		plog(LLV_ERROR, LOCATION, NULL,
706		    "chown(%s, %d, %d): %s\n",
707		    sunaddr.sun_path, adminsock_owner,
708		    adminsock_group, strerror(errno));
709		(void)close(lcconf->sock_admin);
710		return -1;
711	}
712
713	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
714		plog(LLV_ERROR, LOCATION, NULL,
715		    "chmod(%s, 0%03o): %s\n",
716		    sunaddr.sun_path, adminsock_mode, strerror(errno));
717		(void)close(lcconf->sock_admin);
718		return -1;
719	}
720
721	if (listen(lcconf->sock_admin, 5) != 0) {
722		plog(LLV_ERROR, LOCATION, NULL,
723			"listen(sockname:%s): %s\n",
724			sunaddr.sun_path, strerror(errno));
725		(void)close(lcconf->sock_admin);
726		return -1;
727	}
728	plog(LLV_DEBUG, LOCATION, NULL,
729		"open %s as racoon management.\n", sunaddr.sun_path);
730
731	return 0;
732}
733
734int
735admin_close()
736{
737	close(lcconf->sock_admin);
738	return 0;
739}
740#endif
741
742