admin.c revision 1.22
1/*	$NetBSD: admin.c,v 1.22 2008/06/18 06:47:25 mgrooms 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		switch (com->ac_proto) {
218		case ADMIN_PROTO_ISAKMP:
219			buf = dumpph1();
220			if (buf == NULL)
221				ac_errno = ENOMEM;
222			break;
223		case ADMIN_PROTO_IPSEC:
224		case ADMIN_PROTO_AH:
225		case ADMIN_PROTO_ESP: {
226			u_int p;
227			p = admin2pfkey_proto(com->ac_proto);
228			if (p != -1) {
229				buf = pfkey_dump_sadb(p);
230				if (buf == NULL)
231					ac_errno = ENOMEM;
232			} else
233				ac_errno = EINVAL;
234			break;
235		}
236		case ADMIN_PROTO_INTERNAL:
237		default:
238			ac_errno = ENOTSUP;
239			break;
240		}
241		break;
242
243	case ADMIN_FLUSH_SA:
244		switch (com->ac_proto) {
245		case ADMIN_PROTO_ISAKMP:
246			flushph1();
247			break;
248		case ADMIN_PROTO_IPSEC:
249		case ADMIN_PROTO_AH:
250		case ADMIN_PROTO_ESP:
251			pfkey_flush_sadb(com->ac_proto);
252			break;
253		case ADMIN_PROTO_INTERNAL:
254			/*XXX flushph2();*/
255		default:
256			ac_errno = ENOTSUP;
257			break;
258		}
259		break;
260
261	case ADMIN_DELETE_SA: {
262		struct ph1handle *iph1;
263		struct sockaddr *dst;
264		struct sockaddr *src;
265		char *loc, *rem;
266
267		src = (struct sockaddr *)
268			&((struct admin_com_indexes *)
269			    ((caddr_t)com + sizeof(*com)))->src;
270		dst = (struct sockaddr *)
271			&((struct admin_com_indexes *)
272			    ((caddr_t)com + sizeof(*com)))->dst;
273
274		loc = racoon_strdup(saddrwop2str(src));
275		rem = racoon_strdup(saddrwop2str(dst));
276		STRDUP_FATAL(loc);
277		STRDUP_FATAL(rem);
278
279		if ((iph1 = getph1byaddrwop(src, dst)) == NULL) {
280			plog(LLV_ERROR, LOCATION, NULL,
281			    "phase 1 for %s -> %s not found\n", loc, rem);
282		} else {
283			if (iph1->status == PHASE1ST_ESTABLISHED)
284				isakmp_info_send_d1(iph1);
285			purge_remote(iph1);
286		}
287
288		racoon_free(loc);
289		racoon_free(rem);
290		break;
291	}
292
293#ifdef ENABLE_HYBRID
294	case ADMIN_LOGOUT_USER: {
295		struct ph1handle *iph1;
296		char *user;
297		int found = 0;
298
299		if (com->ac_len > sizeof(com) + LOGINLEN + 1) {
300			plog(LLV_ERROR, LOCATION, NULL,
301			    "malformed message (login too long)\n");
302			break;
303		}
304
305		user = (char *)(com + 1);
306		found = purgeph1bylogin(user);
307		plog(LLV_INFO, LOCATION, NULL,
308		    "deleted %d SA for user \"%s\"\n", found, user);
309
310		break;
311	}
312#endif
313
314	case ADMIN_DELETE_ALL_SA_DST: {
315		struct ph1handle *iph1;
316		struct sockaddr *dst;
317		char *loc, *rem;
318
319		dst = (struct sockaddr *)
320			&((struct admin_com_indexes *)
321			    ((caddr_t)com + sizeof(*com)))->dst;
322
323		rem = racoon_strdup(saddrwop2str(dst));
324		STRDUP_FATAL(rem);
325
326		plog(LLV_INFO, LOCATION, NULL,
327		    "Flushing all SAs for peer %s\n", rem);
328
329		while ((iph1 = getph1bydstaddrwop(dst)) != NULL) {
330			loc = racoon_strdup(saddrwop2str(iph1->local));
331			STRDUP_FATAL(loc);
332
333			if (iph1->status == PHASE1ST_ESTABLISHED)
334				isakmp_info_send_d1(iph1);
335			purge_remote(iph1);
336
337			racoon_free(loc);
338		}
339
340		racoon_free(rem);
341		break;
342	}
343
344	case ADMIN_ESTABLISH_SA_PSK: {
345		struct admin_com_psk *acp;
346		char *data;
347
348		acp = (struct admin_com_psk *)
349		    ((char *)com + sizeof(*com) +
350		    sizeof(struct admin_com_indexes));
351
352		idtype = acp->id_type;
353
354		if ((id = vmalloc(acp->id_len)) == NULL) {
355			plog(LLV_ERROR, LOCATION, NULL,
356			    "cannot allocate memory: %s\n",
357			    strerror(errno));
358			break;
359		}
360		data = (char *)(acp + 1);
361		memcpy(id->v, data, id->l);
362
363		if ((key = vmalloc(acp->key_len)) == NULL) {
364			plog(LLV_ERROR, LOCATION, NULL,
365			    "cannot allocate memory: %s\n",
366			    strerror(errno));
367			vfree(id);
368			id = NULL;
369			break;
370		}
371		data = (char *)(data + acp->id_len);
372		memcpy(key->v, data, key->l);
373	}
374	/* FALLTHROUGH */
375	case ADMIN_ESTABLISH_SA: {
376		struct admin_com_indexes *ndx;
377		struct sockaddr *dst;
378		struct sockaddr *src;
379
380		ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com));
381		src = (struct sockaddr *) &ndx->src;
382		dst = (struct sockaddr *) &ndx->dst;
383
384		switch (com->ac_proto) {
385		case ADMIN_PROTO_ISAKMP: {
386			struct ph1handle *ph1;
387			struct remoteconf *rmconf;
388			struct sockaddr *remote = NULL;
389			struct sockaddr *local = NULL;
390			u_int16_t port;
391
392			ac_errno = -1;
393
394			/* connected already? */
395			ph1 = getph1byaddrwop(src, dst);
396			if (ph1 != NULL) {
397				event_list = &ph1->evt_listeners;
398				if (ph1->status == PHASE1ST_ESTABLISHED)
399					ac_errno = EEXIST;
400				else
401					ac_errno = 0;
402				break;
403			}
404
405			/* search appropreate configuration */
406			rmconf = getrmconf(dst);
407			if (rmconf == NULL) {
408				plog(LLV_ERROR, LOCATION, NULL,
409					"no configuration found "
410					"for %s\n", saddrwop2str(dst));
411				goto out1;
412			}
413
414			/* get remote IP address and port number. */
415			if ((remote = dupsaddr(dst)) == NULL)
416				goto out1;
417
418			port = extract_port(rmconf->remote);
419			if (set_port(remote, port) == NULL)
420				goto out1;
421
422			/* get local address */
423			if ((local = dupsaddr(src)) == NULL)
424				goto out1;
425
426			port = getmyaddrsport(local);
427			if (set_port(local, port) == NULL)
428				goto out1;
429
430#ifdef ENABLE_HYBRID
431			/* Set the id and key */
432			if (id && key) {
433				if (xauth_rmconf_used(&rmconf->xauth) == -1)
434					goto out1;
435
436				if (rmconf->xauth->login != NULL) {
437					vfree(rmconf->xauth->login);
438					rmconf->xauth->login = NULL;
439				}
440				if (rmconf->xauth->pass != NULL) {
441					vfree(rmconf->xauth->pass);
442					rmconf->xauth->pass = NULL;
443				}
444
445				rmconf->xauth->login = id;
446				rmconf->xauth->pass = key;
447			}
448#endif
449
450			plog(LLV_INFO, LOCATION, NULL,
451				"accept a request to establish IKE-SA: "
452				"%s\n", saddrwop2str(remote));
453
454			/* begin ident mode */
455			ph1 = isakmp_ph1begin_i(rmconf, remote, local);
456			if (ph1 == NULL)
457				goto out1;
458
459			event_list = &ph1->evt_listeners;
460			ac_errno = 0;
461out1:
462			if (local != NULL)
463				racoon_free(local);
464			if (remote != NULL)
465				racoon_free(remote);
466			break;
467		}
468		case ADMIN_PROTO_AH:
469		case ADMIN_PROTO_ESP: {
470			struct ph2handle *iph2;
471			struct secpolicy *sp_out = NULL, *sp_in = NULL;
472			struct policyindex spidx;
473
474			ac_errno = -1;
475
476			/* got outbound policy */
477			memset(&spidx, 0, sizeof(spidx));
478			spidx.dir = IPSEC_DIR_OUTBOUND;
479			memcpy(&spidx.src, src, sizeof(spidx.src));
480			memcpy(&spidx.dst, dst, sizeof(spidx.dst));
481			spidx.prefs = ndx->prefs;
482			spidx.prefd = ndx->prefd;
483			spidx.ul_proto = ndx->ul_proto;
484
485			sp_out = getsp_r(&spidx);
486			if (sp_out) {
487				plog(LLV_DEBUG, LOCATION, NULL,
488					"suitable outbound SP found: %s.\n",
489					spidx2str(&sp_out->spidx));
490			} else {
491				ac_errno = ENOENT;
492				plog(LLV_NOTIFY, LOCATION, NULL,
493					"no outbound policy found: %s\n",
494					spidx2str(&spidx));
495				break;
496			}
497
498			iph2 = getph2byid(src, dst, sp_out->id);
499			if (iph2 != NULL) {
500				event_list = &iph2->evt_listeners;
501				if (iph2->status == PHASE2ST_ESTABLISHED)
502					ac_errno = EEXIST;
503				else
504					ac_errno = 0;
505				break;
506			}
507
508			/* get inbound policy */
509			memset(&spidx, 0, sizeof(spidx));
510			spidx.dir = IPSEC_DIR_INBOUND;
511			memcpy(&spidx.src, dst, sizeof(spidx.src));
512			memcpy(&spidx.dst, src, sizeof(spidx.dst));
513			spidx.prefs = ndx->prefd;
514			spidx.prefd = ndx->prefs;
515			spidx.ul_proto = ndx->ul_proto;
516
517			sp_in = getsp_r(&spidx);
518			if (sp_in) {
519				plog(LLV_DEBUG, LOCATION, NULL,
520					"suitable inbound SP found: %s.\n",
521					spidx2str(&sp_in->spidx));
522			} else {
523				ac_errno = ENOENT;
524				plog(LLV_NOTIFY, LOCATION, NULL,
525					"no inbound policy found: %s\n",
526				spidx2str(&spidx));
527				break;
528			}
529
530			/* allocate a phase 2 */
531			iph2 = newph2();
532			if (iph2 == NULL) {
533				plog(LLV_ERROR, LOCATION, NULL,
534					"failed to allocate phase2 entry.\n");
535				break;
536			}
537			iph2->side = INITIATOR;
538			iph2->satype = admin2pfkey_proto(com->ac_proto);
539			iph2->spid = sp_out->id;
540			iph2->seq = pk_getseq();
541			iph2->status = PHASE2ST_STATUS2;
542
543			/* set end addresses of SA */
544			iph2->dst = dupsaddr(dst);
545			iph2->src = dupsaddr(src);
546			if (iph2->dst == NULL || iph2->src == NULL) {
547				delph2(iph2);
548				break;
549			}
550
551			if (isakmp_get_sainfo(iph2, sp_out, sp_in) < 0) {
552				delph2(iph2);
553				break;
554			}
555
556			insph2(iph2);
557			if (isakmp_post_acquire(iph2) < 0) {
558				unbindph12(iph2);
559				remph2(iph2);
560				delph2(iph2);
561				break;
562			}
563
564			event_list = &iph2->evt_listeners;
565			ac_errno = 0;
566			break;
567		}
568		default:
569			/* ignore */
570			ac_errno = ENOTSUP;
571		}
572		break;
573	}
574
575	default:
576		plog(LLV_ERROR, LOCATION, NULL,
577			"invalid command: %d\n", com->ac_cmd);
578		ac_errno = ENOTSUP;
579	}
580
581	if ((error = admin_reply(so2, com, ac_errno, buf)) != 0)
582		goto out;
583
584	/* start pushing events if so requested */
585	if ((ac_errno == 0) &&
586	    (com->ac_version >= 1) &&
587	    (com->ac_cmd == ADMIN_SHOW_EVT || event_list != NULL))
588		error = evt_subscribe(event_list, so2);
589out:
590	if (buf != NULL)
591		vfree(buf);
592
593	return error;
594}
595
596static int
597admin_reply(so, req, ac_errno, buf)
598	int so, ac_errno;
599	struct admin_com *req;
600	vchar_t *buf;
601{
602	int tlen;
603	struct admin_com *combuf;
604	char *retbuf = NULL;
605
606	if (buf != NULL)
607		tlen = sizeof(*combuf) + buf->l;
608	else
609		tlen = sizeof(*combuf);
610
611	retbuf = racoon_calloc(1, tlen);
612	if (retbuf == NULL) {
613		plog(LLV_ERROR, LOCATION, NULL,
614			"failed to allocate admin buffer\n");
615		return -1;
616	}
617
618	combuf = (struct admin_com *) retbuf;
619	combuf->ac_len = tlen;
620	combuf->ac_cmd = req->ac_cmd & ~ADMIN_FLAG_VERSION;
621	combuf->ac_errno = ac_errno;
622	combuf->ac_proto = req->ac_proto;
623
624	if (buf != NULL)
625		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
626
627	tlen = send(so, retbuf, tlen, 0);
628	racoon_free(retbuf);
629	if (tlen < 0) {
630		plog(LLV_ERROR, LOCATION, NULL,
631			"failed to send admin command: %s\n",
632			strerror(errno));
633		return -1;
634	}
635
636	return 0;
637}
638
639/* ADMIN_PROTO -> SADB_SATYPE */
640int
641admin2pfkey_proto(proto)
642	u_int proto;
643{
644	switch (proto) {
645	case ADMIN_PROTO_IPSEC:
646		return SADB_SATYPE_UNSPEC;
647	case ADMIN_PROTO_AH:
648		return SADB_SATYPE_AH;
649	case ADMIN_PROTO_ESP:
650		return SADB_SATYPE_ESP;
651	default:
652		plog(LLV_ERROR, LOCATION, NULL,
653			"unsupported proto for admin: %d\n", proto);
654		return -1;
655	}
656	/*NOTREACHED*/
657}
658
659int
660admin_init()
661{
662	if (adminsock_path == NULL) {
663		lcconf->sock_admin = -1;
664		return 0;
665	}
666
667	memset(&sunaddr, 0, sizeof(sunaddr));
668	sunaddr.sun_family = AF_UNIX;
669	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
670		"%s", adminsock_path);
671
672	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
673	if (lcconf->sock_admin == -1) {
674		plog(LLV_ERROR, LOCATION, NULL,
675			"socket: %s\n", strerror(errno));
676		return -1;
677	}
678
679	unlink(sunaddr.sun_path);
680	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
681			sizeof(sunaddr)) != 0) {
682		plog(LLV_ERROR, LOCATION, NULL,
683			"bind(sockname:%s): %s\n",
684			sunaddr.sun_path, strerror(errno));
685		(void)close(lcconf->sock_admin);
686		return -1;
687	}
688
689	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
690		plog(LLV_ERROR, LOCATION, NULL,
691		    "chown(%s, %d, %d): %s\n",
692		    sunaddr.sun_path, adminsock_owner,
693		    adminsock_group, strerror(errno));
694		(void)close(lcconf->sock_admin);
695		return -1;
696	}
697
698	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
699		plog(LLV_ERROR, LOCATION, NULL,
700		    "chmod(%s, 0%03o): %s\n",
701		    sunaddr.sun_path, adminsock_mode, strerror(errno));
702		(void)close(lcconf->sock_admin);
703		return -1;
704	}
705
706	if (listen(lcconf->sock_admin, 5) != 0) {
707		plog(LLV_ERROR, LOCATION, NULL,
708			"listen(sockname:%s): %s\n",
709			sunaddr.sun_path, strerror(errno));
710		(void)close(lcconf->sock_admin);
711		return -1;
712	}
713	plog(LLV_DEBUG, LOCATION, NULL,
714		"open %s as racoon management.\n", sunaddr.sun_path);
715
716	return 0;
717}
718
719int
720admin_close()
721{
722	close(lcconf->sock_admin);
723	return 0;
724}
725#endif
726
727