admin.c revision 1.13
1/*	$NetBSD: admin.c,v 1.13 2006/09/30 15:51:42 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			break;
389		}
390		data = (char *)(data + acp->id_len);
391		memcpy(key->v, data, key->l);
392	}
393	/* FALLTHROUGH */
394	case ADMIN_ESTABLISH_SA:
395	    {
396		struct sockaddr *dst;
397		struct sockaddr *src;
398		src = (struct sockaddr *)
399			&((struct admin_com_indexes *)
400			    ((caddr_t)com + sizeof(*com)))->src;
401		dst = (struct sockaddr *)
402			&((struct admin_com_indexes *)
403			    ((caddr_t)com + sizeof(*com)))->dst;
404
405		switch (com->ac_proto) {
406		case ADMIN_PROTO_ISAKMP:
407		    {
408			struct remoteconf *rmconf;
409			struct sockaddr *remote;
410			struct sockaddr *local;
411
412			/* search appropreate configuration */
413			rmconf = getrmconf(dst);
414			if (rmconf == NULL) {
415				plog(LLV_ERROR, LOCATION, NULL,
416					"no configuration found "
417					"for %s\n", saddrwop2str(dst));
418				com->ac_errno = -1;
419				break;
420			}
421
422			/* get remote IP address and port number. */
423			remote = dupsaddr(dst);
424			if (remote == NULL) {
425				com->ac_errno = -1;
426				break;
427			}
428			switch (remote->sa_family) {
429			case AF_INET:
430				((struct sockaddr_in *)remote)->sin_port =
431					((struct sockaddr_in *)rmconf->remote)->sin_port;
432				break;
433#ifdef INET6
434			case AF_INET6:
435				((struct sockaddr_in6 *)remote)->sin6_port =
436					((struct sockaddr_in6 *)rmconf->remote)->sin6_port;
437				break;
438#endif
439			default:
440				plog(LLV_ERROR, LOCATION, NULL,
441					"invalid family: %d\n",
442					remote->sa_family);
443				com->ac_errno = -1;
444				break;
445			}
446
447			/* get local address */
448			local = dupsaddr(src);
449			if (local == NULL) {
450				com->ac_errno = -1;
451				break;
452			}
453			switch (local->sa_family) {
454			case AF_INET:
455				((struct sockaddr_in *)local)->sin_port =
456					getmyaddrsport(local);
457				break;
458#ifdef INET6
459			case AF_INET6:
460				((struct sockaddr_in6 *)local)->sin6_port =
461					getmyaddrsport(local);
462				break;
463#endif
464			default:
465				plog(LLV_ERROR, LOCATION, NULL,
466					"invalid family: %d\n",
467					local->sa_family);
468				com->ac_errno = -1;
469				break;
470			}
471
472#ifdef ENABLE_HYBRID
473			/* Set the id and key */
474			if (id && key) {
475				if (xauth_rmconf_used(&rmconf->xauth) == -1) {
476					com->ac_errno = -1;
477					break;
478				}
479
480				if (rmconf->xauth->login != NULL) {
481					vfree(rmconf->xauth->login);
482					rmconf->xauth->login = NULL;
483				}
484				if (rmconf->xauth->pass != NULL) {
485					vfree(rmconf->xauth->pass);
486					rmconf->xauth->pass = NULL;
487				}
488
489				rmconf->xauth->login = id;
490				rmconf->xauth->pass = key;
491			}
492#endif
493
494			plog(LLV_INFO, LOCATION, NULL,
495				"accept a request to establish IKE-SA: "
496				"%s\n", saddrwop2str(remote));
497
498			/* begin ident mode */
499			if (isakmp_ph1begin_i(rmconf, remote, local) < 0) {
500				com->ac_errno = -1;
501				break;
502			}
503		    }
504			break;
505		case ADMIN_PROTO_AH:
506		case ADMIN_PROTO_ESP:
507			break;
508		default:
509			/* ignore */
510			com->ac_errno = -1;
511		}
512	    }
513		break;
514
515	default:
516		plog(LLV_ERROR, LOCATION, NULL,
517			"invalid command: %d\n", com->ac_cmd);
518		com->ac_errno = -1;
519	}
520
521	if ((error = admin_reply(so2, com, buf)) != 0)
522		goto out;
523
524	error = 0;
525out:
526	if (buf != NULL)
527		vfree(buf);
528
529	return error;
530}
531
532static int
533admin_reply(so, combuf, buf)
534	int so;
535	struct admin_com *combuf;
536	vchar_t *buf;
537{
538	int tlen;
539	char *retbuf = NULL;
540
541	if (buf != NULL)
542		tlen = sizeof(*combuf) + buf->l;
543	else
544		tlen = sizeof(*combuf);
545
546	retbuf = racoon_calloc(1, tlen);
547	if (retbuf == NULL) {
548		plog(LLV_ERROR, LOCATION, NULL,
549			"failed to allocate admin buffer\n");
550		return -1;
551	}
552
553	memcpy(retbuf, combuf, sizeof(*combuf));
554	((struct admin_com *)retbuf)->ac_len = tlen;
555
556	if (buf != NULL)
557		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
558
559	tlen = send(so, retbuf, tlen, 0);
560	racoon_free(retbuf);
561	if (tlen < 0) {
562		plog(LLV_ERROR, LOCATION, NULL,
563			"failed to send admin command: %s\n",
564			strerror(errno));
565		return -1;
566	}
567
568	return 0;
569}
570
571/* ADMIN_PROTO -> SADB_SATYPE */
572int
573admin2pfkey_proto(proto)
574	u_int proto;
575{
576	switch (proto) {
577	case ADMIN_PROTO_IPSEC:
578		return SADB_SATYPE_UNSPEC;
579	case ADMIN_PROTO_AH:
580		return SADB_SATYPE_AH;
581	case ADMIN_PROTO_ESP:
582		return SADB_SATYPE_ESP;
583	default:
584		plog(LLV_ERROR, LOCATION, NULL,
585			"unsupported proto for admin: %d\n", proto);
586		return -1;
587	}
588	/*NOTREACHED*/
589}
590
591int
592admin_init()
593{
594	if (adminsock_path == NULL) {
595		lcconf->sock_admin = -1;
596		return 0;
597	}
598
599	memset(&sunaddr, 0, sizeof(sunaddr));
600	sunaddr.sun_family = AF_UNIX;
601	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
602		"%s", adminsock_path);
603
604	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
605	if (lcconf->sock_admin == -1) {
606		plog(LLV_ERROR, LOCATION, NULL,
607			"socket: %s\n", strerror(errno));
608		return -1;
609	}
610
611	unlink(sunaddr.sun_path);
612	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
613			sizeof(sunaddr)) != 0) {
614		plog(LLV_ERROR, LOCATION, NULL,
615			"bind(sockname:%s): %s\n",
616			sunaddr.sun_path, strerror(errno));
617		(void)close(lcconf->sock_admin);
618		return -1;
619	}
620
621	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
622		plog(LLV_ERROR, LOCATION, NULL,
623		    "chown(%s, %d, %d): %s\n",
624		    sunaddr.sun_path, adminsock_owner,
625		    adminsock_group, strerror(errno));
626		(void)close(lcconf->sock_admin);
627		return -1;
628	}
629
630	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
631		plog(LLV_ERROR, LOCATION, NULL,
632		    "chmod(%s, 0%03o): %s\n",
633		    sunaddr.sun_path, adminsock_mode, strerror(errno));
634		(void)close(lcconf->sock_admin);
635		return -1;
636	}
637
638	if (listen(lcconf->sock_admin, 5) != 0) {
639		plog(LLV_ERROR, LOCATION, NULL,
640			"listen(sockname:%s): %s\n",
641			sunaddr.sun_path, strerror(errno));
642		(void)close(lcconf->sock_admin);
643		return -1;
644	}
645	plog(LLV_DEBUG, LOCATION, NULL,
646		"open %s as racoon management.\n", sunaddr.sun_path);
647
648	return 0;
649}
650
651int
652admin_close()
653{
654	close(lcconf->sock_admin);
655	return 0;
656}
657#endif
658
659