admin.c revision 1.17
1/*	$NetBSD: admin.c,v 1.17 2006/10/03 20:43:10 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 = NULL;
196		int len;
197
198		com->ac_errno = -1;
199
200		if (sched_dump(&p, &len) == -1)
201			goto out2;
202
203		if ((buf = vmalloc(len)) == NULL)
204			goto out2;
205
206		memcpy(buf->v, p, len);
207
208		com->ac_errno = 0;
209out2:
210		racoon_free(p);
211		break;
212	}
213
214	case ADMIN_SHOW_EVT:
215		/* It's not really an error, don't force racoonctl to quit */
216		if ((buf = evt_dump()) == NULL)
217			com->ac_errno = 0;
218		break;
219
220	case ADMIN_SHOW_SA:
221	case ADMIN_FLUSH_SA:
222	    {
223		switch (com->ac_proto) {
224		case ADMIN_PROTO_ISAKMP:
225			switch (com->ac_cmd) {
226			case ADMIN_SHOW_SA:
227				buf = dumpph1();
228				if (buf == NULL)
229					com->ac_errno = -1;
230				break;
231			case ADMIN_FLUSH_SA:
232				flushph1();
233				break;
234			}
235			break;
236		case ADMIN_PROTO_IPSEC:
237		case ADMIN_PROTO_AH:
238		case ADMIN_PROTO_ESP:
239			switch (com->ac_cmd) {
240			case ADMIN_SHOW_SA:
241			    {
242				u_int p;
243				p = admin2pfkey_proto(com->ac_proto);
244				if (p == -1)
245					goto out;
246				buf = pfkey_dump_sadb(p);
247				if (buf == NULL)
248					com->ac_errno = -1;
249			    }
250				break;
251			case ADMIN_FLUSH_SA:
252				pfkey_flush_sadb(com->ac_proto);
253				break;
254			}
255			break;
256
257		case ADMIN_PROTO_INTERNAL:
258			switch (com->ac_cmd) {
259			case ADMIN_SHOW_SA:
260				buf = NULL; /*XXX dumpph2(&error);*/
261				if (buf == NULL)
262					com->ac_errno = error;
263				break;
264			case ADMIN_FLUSH_SA:
265				/*XXX flushph2();*/
266				com->ac_errno = 0;
267				break;
268			}
269			break;
270
271		default:
272			/* ignore */
273			com->ac_errno = -1;
274		}
275	    }
276		break;
277
278	case ADMIN_DELETE_SA: {
279		struct ph1handle *iph1;
280		struct sockaddr *dst;
281		struct sockaddr *src;
282		char *loc, *rem;
283
284		src = (struct sockaddr *)
285			&((struct admin_com_indexes *)
286			    ((caddr_t)com + sizeof(*com)))->src;
287		dst = (struct sockaddr *)
288			&((struct admin_com_indexes *)
289			    ((caddr_t)com + sizeof(*com)))->dst;
290
291		loc = racoon_strdup(saddrwop2str(src));
292		rem = racoon_strdup(saddrwop2str(dst));
293		STRDUP_FATAL(loc);
294		STRDUP_FATAL(rem);
295
296		if ((iph1 = getph1byaddrwop(src, dst)) == NULL) {
297			plog(LLV_ERROR, LOCATION, NULL,
298			    "phase 1 for %s -> %s not found\n", loc, rem);
299		} else {
300			if (iph1->status == PHASE1ST_ESTABLISHED)
301				isakmp_info_send_d1(iph1);
302			purge_remote(iph1);
303		}
304
305		racoon_free(loc);
306		racoon_free(rem);
307
308		break;
309	}
310
311#ifdef ENABLE_HYBRID
312	case ADMIN_LOGOUT_USER: {
313		struct ph1handle *iph1;
314		char *user;
315		int found = 0;
316
317		if (com->ac_len > sizeof(com) + LOGINLEN + 1) {
318			plog(LLV_ERROR, LOCATION, NULL,
319			    "malformed message (login too long)\n");
320			break;
321		}
322
323		user = (char *)(com + 1);
324		found = purgeph1bylogin(user);
325		plog(LLV_INFO, LOCATION, NULL,
326		    "deleted %d SA for user \"%s\"\n", found, user);
327
328		break;
329	}
330#endif
331
332	case ADMIN_DELETE_ALL_SA_DST: {
333		struct ph1handle *iph1;
334		struct sockaddr *dst;
335		char *loc, *rem;
336
337		dst = (struct sockaddr *)
338			&((struct admin_com_indexes *)
339			    ((caddr_t)com + sizeof(*com)))->dst;
340
341		rem = racoon_strdup(saddrwop2str(dst));
342		STRDUP_FATAL(rem);
343
344		plog(LLV_INFO, LOCATION, NULL,
345		    "Flushing all SAs for peer %s\n", rem);
346
347		while ((iph1 = getph1bydstaddrwop(dst)) != NULL) {
348			loc = racoon_strdup(saddrwop2str(iph1->local));
349			STRDUP_FATAL(loc);
350
351			if (iph1->status == PHASE1ST_ESTABLISHED)
352				isakmp_info_send_d1(iph1);
353			purge_remote(iph1);
354
355			racoon_free(loc);
356		}
357
358		racoon_free(rem);
359
360		break;
361	}
362
363	case ADMIN_ESTABLISH_SA_PSK: {
364		struct admin_com_psk *acp;
365		char *data;
366
367		com->ac_cmd = ADMIN_ESTABLISH_SA;
368
369		acp = (struct admin_com_psk *)
370		    ((char *)com + sizeof(*com) +
371		    sizeof(struct admin_com_indexes));
372
373		idtype = acp->id_type;
374
375		if ((id = vmalloc(acp->id_len)) == NULL) {
376			plog(LLV_ERROR, LOCATION, NULL,
377			    "cannot allocate memory: %s\n",
378			    strerror(errno));
379			break;
380		}
381		data = (char *)(acp + 1);
382		memcpy(id->v, data, id->l);
383
384		if ((key = vmalloc(acp->key_len)) == NULL) {
385			plog(LLV_ERROR, LOCATION, NULL,
386			    "cannot allocate memory: %s\n",
387			    strerror(errno));
388			vfree(id);
389			id = NULL;
390			break;
391		}
392		data = (char *)(data + acp->id_len);
393		memcpy(key->v, data, key->l);
394	}
395	/* FALLTHROUGH */
396	case ADMIN_ESTABLISH_SA:
397	    {
398		struct sockaddr *dst;
399		struct sockaddr *src;
400		src = (struct sockaddr *)
401			&((struct admin_com_indexes *)
402			    ((caddr_t)com + sizeof(*com)))->src;
403		dst = (struct sockaddr *)
404			&((struct admin_com_indexes *)
405			    ((caddr_t)com + sizeof(*com)))->dst;
406
407		switch (com->ac_proto) {
408		case ADMIN_PROTO_ISAKMP: {
409			struct remoteconf *rmconf;
410			struct sockaddr *remote = NULL;
411			struct sockaddr *local = NULL;
412			u_int16_t port;
413
414			com->ac_errno = -1;
415
416			/* search appropreate configuration */
417			rmconf = getrmconf(dst);
418			if (rmconf == NULL) {
419				plog(LLV_ERROR, LOCATION, NULL,
420					"no configuration found "
421					"for %s\n", saddrwop2str(dst));
422				goto out1;
423			}
424
425			/* get remote IP address and port number. */
426			if ((remote = dupsaddr(dst)) == NULL)
427				goto out1;
428
429			port = extract_port(rmconf->remote);
430			if (set_port(remote, port) == NULL)
431				goto out1;
432
433			/* get local address */
434			if ((local = dupsaddr(src)) == NULL)
435				goto out1;
436
437			port = ntohs(getmyaddrsport(local));
438			if (set_port(local, port) == NULL)
439				goto out1;
440
441#ifdef ENABLE_HYBRID
442			/* Set the id and key */
443			if (id && key) {
444				if (xauth_rmconf_used(&rmconf->xauth) == -1)
445					goto out1;
446
447				if (rmconf->xauth->login != NULL) {
448					vfree(rmconf->xauth->login);
449					rmconf->xauth->login = NULL;
450				}
451				if (rmconf->xauth->pass != NULL) {
452					vfree(rmconf->xauth->pass);
453					rmconf->xauth->pass = NULL;
454				}
455
456				rmconf->xauth->login = id;
457				rmconf->xauth->pass = key;
458			}
459#endif
460
461			plog(LLV_INFO, LOCATION, NULL,
462				"accept a request to establish IKE-SA: "
463				"%s\n", saddrwop2str(remote));
464
465			/* begin ident mode */
466			if (isakmp_ph1begin_i(rmconf, remote, local) < 0)
467				goto out1;
468
469			com->ac_errno = 0;
470out1:
471			if (local != NULL)
472				racoon_free(local);
473			if (remote != NULL)
474				racoon_free(remote);
475			break;
476		}
477		case ADMIN_PROTO_AH:
478		case ADMIN_PROTO_ESP:
479			break;
480		default:
481			/* ignore */
482			com->ac_errno = -1;
483		}
484	    }
485		break;
486
487	default:
488		plog(LLV_ERROR, LOCATION, NULL,
489			"invalid command: %d\n", com->ac_cmd);
490		com->ac_errno = -1;
491	}
492
493	if ((error = admin_reply(so2, com, buf)) != 0)
494		goto out;
495
496	error = 0;
497out:
498	if (buf != NULL)
499		vfree(buf);
500
501	return error;
502}
503
504static int
505admin_reply(so, combuf, buf)
506	int so;
507	struct admin_com *combuf;
508	vchar_t *buf;
509{
510	int tlen;
511	char *retbuf = NULL;
512
513	if (buf != NULL)
514		tlen = sizeof(*combuf) + buf->l;
515	else
516		tlen = sizeof(*combuf);
517
518	retbuf = racoon_calloc(1, tlen);
519	if (retbuf == NULL) {
520		plog(LLV_ERROR, LOCATION, NULL,
521			"failed to allocate admin buffer\n");
522		return -1;
523	}
524
525	memcpy(retbuf, combuf, sizeof(*combuf));
526	((struct admin_com *)retbuf)->ac_len = tlen;
527
528	if (buf != NULL)
529		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
530
531	tlen = send(so, retbuf, tlen, 0);
532	racoon_free(retbuf);
533	if (tlen < 0) {
534		plog(LLV_ERROR, LOCATION, NULL,
535			"failed to send admin command: %s\n",
536			strerror(errno));
537		return -1;
538	}
539
540	return 0;
541}
542
543/* ADMIN_PROTO -> SADB_SATYPE */
544int
545admin2pfkey_proto(proto)
546	u_int proto;
547{
548	switch (proto) {
549	case ADMIN_PROTO_IPSEC:
550		return SADB_SATYPE_UNSPEC;
551	case ADMIN_PROTO_AH:
552		return SADB_SATYPE_AH;
553	case ADMIN_PROTO_ESP:
554		return SADB_SATYPE_ESP;
555	default:
556		plog(LLV_ERROR, LOCATION, NULL,
557			"unsupported proto for admin: %d\n", proto);
558		return -1;
559	}
560	/*NOTREACHED*/
561}
562
563int
564admin_init()
565{
566	if (adminsock_path == NULL) {
567		lcconf->sock_admin = -1;
568		return 0;
569	}
570
571	memset(&sunaddr, 0, sizeof(sunaddr));
572	sunaddr.sun_family = AF_UNIX;
573	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
574		"%s", adminsock_path);
575
576	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
577	if (lcconf->sock_admin == -1) {
578		plog(LLV_ERROR, LOCATION, NULL,
579			"socket: %s\n", strerror(errno));
580		return -1;
581	}
582
583	unlink(sunaddr.sun_path);
584	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
585			sizeof(sunaddr)) != 0) {
586		plog(LLV_ERROR, LOCATION, NULL,
587			"bind(sockname:%s): %s\n",
588			sunaddr.sun_path, strerror(errno));
589		(void)close(lcconf->sock_admin);
590		return -1;
591	}
592
593	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
594		plog(LLV_ERROR, LOCATION, NULL,
595		    "chown(%s, %d, %d): %s\n",
596		    sunaddr.sun_path, adminsock_owner,
597		    adminsock_group, strerror(errno));
598		(void)close(lcconf->sock_admin);
599		return -1;
600	}
601
602	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
603		plog(LLV_ERROR, LOCATION, NULL,
604		    "chmod(%s, 0%03o): %s\n",
605		    sunaddr.sun_path, adminsock_mode, strerror(errno));
606		(void)close(lcconf->sock_admin);
607		return -1;
608	}
609
610	if (listen(lcconf->sock_admin, 5) != 0) {
611		plog(LLV_ERROR, LOCATION, NULL,
612			"listen(sockname:%s): %s\n",
613			sunaddr.sun_path, strerror(errno));
614		(void)close(lcconf->sock_admin);
615		return -1;
616	}
617	plog(LLV_DEBUG, LOCATION, NULL,
618		"open %s as racoon management.\n", sunaddr.sun_path);
619
620	return 0;
621}
622
623int
624admin_close()
625{
626	close(lcconf->sock_admin);
627	return 0;
628}
629#endif
630
631