admin.c revision 1.19
1/*	$NetBSD: admin.c,v 1.19 2008/03/06 00:34:11 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 "admin.h"
80#include "admin_var.h"
81#include "isakmp_inf.h"
82#ifdef ENABLE_HYBRID
83#include "isakmp_cfg.h"
84#endif
85#include "session.h"
86#include "gcmalloc.h"
87
88#ifdef ENABLE_ADMINPORT
89char *adminsock_path = ADMINSOCK_PATH;
90uid_t adminsock_owner = 0;
91gid_t adminsock_group = 0;
92mode_t adminsock_mode = 0600;
93
94static struct sockaddr_un sunaddr;
95static int admin_process __P((int, char *));
96static int admin_reply __P((int, struct admin_com *, int, vchar_t *));
97
98int
99admin_handler()
100{
101	int so2;
102	struct sockaddr_storage from;
103	socklen_t fromlen = sizeof(from);
104	struct admin_com com;
105	char *combuf = NULL;
106	int len, error = -1;
107
108	so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen);
109	if (so2 < 0) {
110		plog(LLV_ERROR, LOCATION, NULL,
111			"failed to accept admin command: %s\n",
112			strerror(errno));
113		return -1;
114	}
115
116	/* get buffer length */
117	while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) {
118		if (errno == EINTR)
119			continue;
120		plog(LLV_ERROR, LOCATION, NULL,
121			"failed to recv admin command: %s\n",
122			strerror(errno));
123		goto end;
124	}
125
126	/* sanity check */
127	if (len < sizeof(com)) {
128		plog(LLV_ERROR, LOCATION, NULL,
129			"invalid header length of admin command\n");
130		goto end;
131	}
132
133	/* get buffer to receive */
134	if ((combuf = racoon_malloc(com.ac_len)) == 0) {
135		plog(LLV_ERROR, LOCATION, NULL,
136			"failed to alloc buffer for admin command\n");
137		goto end;
138	}
139
140	/* get real data */
141	while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) {
142		if (errno == EINTR)
143			continue;
144		plog(LLV_ERROR, LOCATION, NULL,
145			"failed to recv admin command: %s\n",
146			strerror(errno));
147		goto end;
148	}
149
150	error = admin_process(so2, combuf);
151
152end:
153	if (error == -2) {
154		plog(LLV_DEBUG, LOCATION, NULL,
155			"[%d] admin connection established\n", so2);
156	} else {
157		(void)close(so2);
158	}
159
160	if (combuf)
161		racoon_free(combuf);
162
163	return error;
164}
165
166/*
167 * main child's process.
168 */
169static int
170admin_process(so2, combuf)
171	int so2;
172	char *combuf;
173{
174	struct admin_com *com = (struct admin_com *)combuf;
175	vchar_t *buf = NULL;
176	vchar_t *id = NULL;
177	vchar_t *key = NULL;
178	int idtype = 0;
179	int error = 0, ac_errno = 0;
180	struct evt_listener_list *event_list = NULL;
181
182	if (com->ac_cmd & ADMIN_FLAG_VERSION)
183		com->ac_cmd &= ~ADMIN_FLAG_VERSION;
184	else
185		com->ac_version = 0;
186
187	switch (com->ac_cmd) {
188	case ADMIN_RELOAD_CONF:
189		signal_handler(SIGHUP);
190		break;
191
192	case ADMIN_SHOW_SCHED: {
193		caddr_t p = NULL;
194		int len;
195
196		if (sched_dump(&p, &len) != -1) {
197			buf = vmalloc(len);
198			if (buf != NULL)
199				memcpy(buf->v, p, len);
200			else
201				ac_errno = ENOMEM;
202			racoon_free(p);
203		} else
204			ac_errno = ENOMEM;
205		break;
206	}
207
208	case ADMIN_SHOW_EVT:
209		if (com->ac_version == 0) {
210			buf = evt_dump();
211			ac_errno = 0;
212		}
213		break;
214
215	case ADMIN_SHOW_SA:
216	case ADMIN_FLUSH_SA:
217		switch (com->ac_proto) {
218		case ADMIN_PROTO_ISAKMP:
219			switch (com->ac_cmd) {
220			case ADMIN_SHOW_SA:
221				buf = dumpph1();
222				if (buf == NULL)
223					ac_errno = ENOMEM;
224				break;
225			case ADMIN_FLUSH_SA:
226				flushph1();
227				break;
228			default:
229				ac_errno = ENOTSUP;
230				break;
231			}
232			break;
233		case ADMIN_PROTO_IPSEC:
234		case ADMIN_PROTO_AH:
235		case ADMIN_PROTO_ESP:
236			switch (com->ac_cmd) {
237			case ADMIN_SHOW_SA: {
238				u_int p;
239				p = admin2pfkey_proto(com->ac_proto);
240				if (p != -1) {
241					buf = pfkey_dump_sadb(p);
242					if (buf == NULL)
243						ac_errno = ENOMEM;
244				} else
245					ac_errno = EINVAL;
246				break;
247			}
248			case ADMIN_FLUSH_SA:
249				pfkey_flush_sadb(com->ac_proto);
250				break;
251			default:
252				ac_errno = ENOTSUP;
253				break;
254			}
255			break;
256		case ADMIN_PROTO_INTERNAL:
257			switch (com->ac_cmd) {
258			case ADMIN_SHOW_SA:
259				buf = NULL; /*XXX dumpph2(&error);*/
260				ac_errno = ENOTSUP;
261				break;
262			case ADMIN_FLUSH_SA:
263				/*XXX flushph2();*/
264				break;
265			default:
266				ac_errno = ENOTSUP;
267				break;
268			}
269			break;
270		default:
271			ac_errno = ENOTSUP;
272		}
273		break;
274
275	case ADMIN_DELETE_SA: {
276		struct ph1handle *iph1;
277		struct sockaddr *dst;
278		struct sockaddr *src;
279		char *loc, *rem;
280
281		src = (struct sockaddr *)
282			&((struct admin_com_indexes *)
283			    ((caddr_t)com + sizeof(*com)))->src;
284		dst = (struct sockaddr *)
285			&((struct admin_com_indexes *)
286			    ((caddr_t)com + sizeof(*com)))->dst;
287
288		loc = racoon_strdup(saddrwop2str(src));
289		rem = racoon_strdup(saddrwop2str(dst));
290		STRDUP_FATAL(loc);
291		STRDUP_FATAL(rem);
292
293		if ((iph1 = getph1byaddrwop(src, dst)) == NULL) {
294			plog(LLV_ERROR, LOCATION, NULL,
295			    "phase 1 for %s -> %s not found\n", loc, rem);
296		} else {
297			if (iph1->status == PHASE1ST_ESTABLISHED)
298				isakmp_info_send_d1(iph1);
299			purge_remote(iph1);
300		}
301
302		racoon_free(loc);
303		racoon_free(rem);
304		break;
305	}
306
307#ifdef ENABLE_HYBRID
308	case ADMIN_LOGOUT_USER: {
309		struct ph1handle *iph1;
310		char *user;
311		int found = 0;
312
313		if (com->ac_len > sizeof(com) + LOGINLEN + 1) {
314			plog(LLV_ERROR, LOCATION, NULL,
315			    "malformed message (login too long)\n");
316			break;
317		}
318
319		user = (char *)(com + 1);
320		found = purgeph1bylogin(user);
321		plog(LLV_INFO, LOCATION, NULL,
322		    "deleted %d SA for user \"%s\"\n", found, user);
323
324		break;
325	}
326#endif
327
328	case ADMIN_DELETE_ALL_SA_DST: {
329		struct ph1handle *iph1;
330		struct sockaddr *dst;
331		char *loc, *rem;
332
333		dst = (struct sockaddr *)
334			&((struct admin_com_indexes *)
335			    ((caddr_t)com + sizeof(*com)))->dst;
336
337		rem = racoon_strdup(saddrwop2str(dst));
338		STRDUP_FATAL(rem);
339
340		plog(LLV_INFO, LOCATION, NULL,
341		    "Flushing all SAs for peer %s\n", rem);
342
343		while ((iph1 = getph1bydstaddrwop(dst)) != NULL) {
344			loc = racoon_strdup(saddrwop2str(iph1->local));
345			STRDUP_FATAL(loc);
346
347			if (iph1->status == PHASE1ST_ESTABLISHED)
348				isakmp_info_send_d1(iph1);
349			purge_remote(iph1);
350
351			racoon_free(loc);
352		}
353
354		racoon_free(rem);
355		break;
356	}
357
358	case ADMIN_ESTABLISH_SA_PSK: {
359		struct admin_com_psk *acp;
360		char *data;
361
362		acp = (struct admin_com_psk *)
363		    ((char *)com + sizeof(*com) +
364		    sizeof(struct admin_com_indexes));
365
366		idtype = acp->id_type;
367
368		if ((id = vmalloc(acp->id_len)) == NULL) {
369			plog(LLV_ERROR, LOCATION, NULL,
370			    "cannot allocate memory: %s\n",
371			    strerror(errno));
372			break;
373		}
374		data = (char *)(acp + 1);
375		memcpy(id->v, data, id->l);
376
377		if ((key = vmalloc(acp->key_len)) == NULL) {
378			plog(LLV_ERROR, LOCATION, NULL,
379			    "cannot allocate memory: %s\n",
380			    strerror(errno));
381			vfree(id);
382			id = NULL;
383			break;
384		}
385		data = (char *)(data + acp->id_len);
386		memcpy(key->v, data, key->l);
387	}
388	/* FALLTHROUGH */
389	case ADMIN_ESTABLISH_SA: {
390		struct sockaddr *dst;
391		struct sockaddr *src;
392		src = (struct sockaddr *)
393			&((struct admin_com_indexes *)
394			    ((caddr_t)com + sizeof(*com)))->src;
395		dst = (struct sockaddr *)
396			&((struct admin_com_indexes *)
397			    ((caddr_t)com + sizeof(*com)))->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			ac_errno = ENOTSUP;
486			break;
487		default:
488			/* ignore */
489			ac_errno = ENOTSUP;
490		}
491		break;
492	}
493
494	default:
495		plog(LLV_ERROR, LOCATION, NULL,
496			"invalid command: %d\n", com->ac_cmd);
497		ac_errno = ENOTSUP;
498	}
499
500	if ((error = admin_reply(so2, com, ac_errno, buf)) != 0)
501		goto out;
502
503	/* start pushing events if so requested */
504	if ((ac_errno == 0) &&
505	    (com->ac_version >= 1) &&
506	    (com->ac_cmd == ADMIN_SHOW_EVT || event_list != NULL))
507		error = evt_subscribe(event_list, so2);
508out:
509	if (buf != NULL)
510		vfree(buf);
511
512	return error;
513}
514
515static int
516admin_reply(so, req, ac_errno, buf)
517	int so, ac_errno;
518	struct admin_com *req;
519	vchar_t *buf;
520{
521	int tlen;
522	struct admin_com *combuf;
523	char *retbuf = NULL;
524
525	if (buf != NULL)
526		tlen = sizeof(*combuf) + buf->l;
527	else
528		tlen = sizeof(*combuf);
529
530	retbuf = racoon_calloc(1, tlen);
531	if (retbuf == NULL) {
532		plog(LLV_ERROR, LOCATION, NULL,
533			"failed to allocate admin buffer\n");
534		return -1;
535	}
536
537	combuf = (struct admin_com *) retbuf;
538	combuf->ac_len = tlen;
539	combuf->ac_cmd = req->ac_cmd & ~ADMIN_FLAG_VERSION;
540	combuf->ac_errno = ac_errno;
541	combuf->ac_proto = req->ac_proto;
542
543	if (buf != NULL)
544		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
545
546	tlen = send(so, retbuf, tlen, 0);
547	racoon_free(retbuf);
548	if (tlen < 0) {
549		plog(LLV_ERROR, LOCATION, NULL,
550			"failed to send admin command: %s\n",
551			strerror(errno));
552		return -1;
553	}
554
555	return 0;
556}
557
558/* ADMIN_PROTO -> SADB_SATYPE */
559int
560admin2pfkey_proto(proto)
561	u_int proto;
562{
563	switch (proto) {
564	case ADMIN_PROTO_IPSEC:
565		return SADB_SATYPE_UNSPEC;
566	case ADMIN_PROTO_AH:
567		return SADB_SATYPE_AH;
568	case ADMIN_PROTO_ESP:
569		return SADB_SATYPE_ESP;
570	default:
571		plog(LLV_ERROR, LOCATION, NULL,
572			"unsupported proto for admin: %d\n", proto);
573		return -1;
574	}
575	/*NOTREACHED*/
576}
577
578int
579admin_init()
580{
581	if (adminsock_path == NULL) {
582		lcconf->sock_admin = -1;
583		return 0;
584	}
585
586	memset(&sunaddr, 0, sizeof(sunaddr));
587	sunaddr.sun_family = AF_UNIX;
588	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
589		"%s", adminsock_path);
590
591	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
592	if (lcconf->sock_admin == -1) {
593		plog(LLV_ERROR, LOCATION, NULL,
594			"socket: %s\n", strerror(errno));
595		return -1;
596	}
597
598	unlink(sunaddr.sun_path);
599	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
600			sizeof(sunaddr)) != 0) {
601		plog(LLV_ERROR, LOCATION, NULL,
602			"bind(sockname:%s): %s\n",
603			sunaddr.sun_path, strerror(errno));
604		(void)close(lcconf->sock_admin);
605		return -1;
606	}
607
608	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
609		plog(LLV_ERROR, LOCATION, NULL,
610		    "chown(%s, %d, %d): %s\n",
611		    sunaddr.sun_path, adminsock_owner,
612		    adminsock_group, strerror(errno));
613		(void)close(lcconf->sock_admin);
614		return -1;
615	}
616
617	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
618		plog(LLV_ERROR, LOCATION, NULL,
619		    "chmod(%s, 0%03o): %s\n",
620		    sunaddr.sun_path, adminsock_mode, strerror(errno));
621		(void)close(lcconf->sock_admin);
622		return -1;
623	}
624
625	if (listen(lcconf->sock_admin, 5) != 0) {
626		plog(LLV_ERROR, LOCATION, NULL,
627			"listen(sockname:%s): %s\n",
628			sunaddr.sun_path, strerror(errno));
629		(void)close(lcconf->sock_admin);
630		return -1;
631	}
632	plog(LLV_DEBUG, LOCATION, NULL,
633		"open %s as racoon management.\n", sunaddr.sun_path);
634
635	return 0;
636}
637
638int
639admin_close()
640{
641	close(lcconf->sock_admin);
642	return 0;
643}
644#endif
645
646