xref: /openbsd/usr.sbin/ikectl/ikectl.c (revision 3cab2bb3)
1 /*	$OpenBSD: ikectl.c,v 1.26 2020/06/10 17:44:44 kn Exp $	*/
2 
3 /*
4  * Copyright (c) 2007-2013 Reyk Floeter <reyk@openbsd.org>
5  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
7  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/queue.h>
25 #include <sys/un.h>
26 #include <sys/tree.h>
27 
28 #include <err.h>
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <event.h>
35 
36 #include "iked.h"
37 #include "parser.h"
38 
39 __dead void	 usage(void);
40 
41 struct imsgname {
42 	int type;
43 	char *name;
44 	void (*func)(struct imsg *);
45 };
46 
47 struct imsgname *monitor_lookup(uint8_t);
48 void		 monitor_id(struct imsg *);
49 int		 monitor(struct imsg *);
50 
51 int		 show_string(struct imsg *);
52 
53 int		 ca_opt(struct parse_result *);
54 
55 struct imsgname imsgs[] = {
56 	{ IMSG_CTL_OK,			"ok",			NULL },
57 	{ IMSG_CTL_FAIL,		"fail",			NULL },
58 	{ IMSG_CTL_VERBOSE,		"verbose",		NULL },
59 	{ IMSG_CTL_RELOAD,		"reload",		NULL },
60 	{ IMSG_CTL_RESET,		"reset",		NULL },
61 	{ IMSG_CTL_SHOW_SA,		"show sa",		NULL },
62 	{ 0,				NULL,			NULL }
63 
64 };
65 struct imsgname imsgunknown = {
66 	-1,				"<unknown>",		NULL
67 };
68 
69 struct imsgbuf	*ibuf;
70 
71 __dead void
72 usage(void)
73 {
74 	extern char *__progname;
75 
76 	fprintf(stderr, "usage: %s [-q] [-s socket] command [arg ...]\n",
77 	    __progname);
78 	exit(1);
79 }
80 
81 int
82 ca_opt(struct parse_result *res)
83 {
84 	struct ca	*ca;
85 	size_t		 len;
86 	char		*p;
87 
88 	ca = ca_setup(res->caname, (res->action == CA_CREATE),
89 	    res->quiet, res->pass);
90 	if (ca == NULL)
91 		errx(1, "ca_setup failed");
92 
93 	/* assume paths are relative to /etc if not absolute */
94 	if (res->path && (res->path[0] != '.') && (res->path[0] != '/')) {
95 		len = 5 + strlen(res->path) + 1;
96 		if ((p = malloc(len)) == NULL)
97 			err(1, "malloc");
98 		snprintf(p, len, "/etc/%s", res->path);
99 		free(res->path);
100 		res->path = p;
101 	}
102 
103 	switch (res->action) {
104 	case CA_CREATE:
105 		ca_create(ca);
106 		break;
107 	case CA_DELETE:
108 		ca_delete(ca);
109 		break;
110 	case CA_INSTALL:
111 		ca_install(ca, res->path);
112 		break;
113 	case CA_EXPORT:
114 		ca_export(ca, NULL, res->peer, res->pass);
115 		break;
116 	case CA_CERT_CREATE:
117 	case CA_SERVER:
118 	case CA_CLIENT:
119 	case CA_OCSP:
120 		ca_certificate(ca, res->host, res->htype, res->action);
121 		break;
122 	case CA_CERT_DELETE:
123 		ca_delkey(ca, res->host);
124 		break;
125 	case CA_CERT_INSTALL:
126 		ca_cert_install(ca, res->host, res->path);
127 		break;
128 	case CA_CERT_EXPORT:
129 		ca_export(ca, res->host, res->peer, res->pass);
130 		break;
131 	case CA_CERT_REVOKE:
132 		ca_revoke(ca, res->host);
133 		break;
134 	case SHOW_CA_CERTIFICATES:
135 		ca_show_certs(ca, res->host);
136 		break;
137 	case CA_KEY_CREATE:
138 		ca_key_create(ca, res->host);
139 		break;
140 	case CA_KEY_DELETE:
141 		ca_key_delete(ca, res->host);
142 		break;
143 	case CA_KEY_INSTALL:
144 		ca_key_install(ca, res->host, res->path);
145 		break;
146 	case CA_KEY_IMPORT:
147 		ca_key_import(ca, res->host, res->path);
148 		break;
149 	default:
150 		break;
151 	}
152 
153 	return (0);
154 }
155 
156 int
157 main(int argc, char *argv[])
158 {
159 	struct sockaddr_un	 sun;
160 	struct parse_result	*res;
161 	struct imsg		 imsg;
162 	int			 ctl_sock;
163 	int			 done = 1;
164 	int			 n;
165 	int			 ch;
166 	int			 v = 0;
167 	int			 quiet = 0;
168 	const char		*sock = IKED_SOCKET;
169 
170 	while ((ch = getopt(argc, argv, "qs:")) != -1) {
171 		switch (ch) {
172 		case 'q':
173 			quiet = 1;
174 			break;
175 		case 's':
176 			sock = optarg;
177 			break;
178 		default:
179 			usage();
180 			/* NOTREACHED */
181 		}
182 	}
183 	argc -= optind;
184 	argv += optind;
185 
186 	/* parse options */
187 	if ((res = parse(argc, argv)) == NULL)
188 		exit(1);
189 
190 	res->quiet = quiet;
191 
192 	switch (res->action) {
193 	case CA_CREATE:
194 	case CA_DELETE:
195 	case CA_INSTALL:
196 	case CA_EXPORT:
197 	case CA_CERT_CREATE:
198 	case CA_CLIENT:
199 	case CA_SERVER:
200 	case CA_OCSP:
201 	case CA_CERT_DELETE:
202 	case CA_CERT_INSTALL:
203 	case CA_CERT_EXPORT:
204 	case CA_CERT_REVOKE:
205 	case SHOW_CA:
206 	case SHOW_CA_CERTIFICATES:
207 	case CA_KEY_CREATE:
208 	case CA_KEY_DELETE:
209 	case CA_KEY_INSTALL:
210 	case CA_KEY_IMPORT:
211 		if (pledge("stdio proc exec rpath wpath cpath fattr tty", NULL)
212 		    == -1)
213 			err(1, "pledge");
214 		ca_opt(res);
215 		break;
216 	case NONE:
217 		usage();
218 		break;
219 	default:
220 		goto connect;
221 	}
222 
223 	return (0);
224 
225  connect:
226 	/* connect to iked control socket */
227 	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
228 		err(1, "socket");
229 
230 	bzero(&sun, sizeof(sun));
231 	sun.sun_family = AF_UNIX;
232 	strlcpy(sun.sun_path, sock, sizeof(sun.sun_path));
233  reconnect:
234 	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
235 		/* Keep retrying if running in monitor mode */
236 		if (res->action == MONITOR &&
237 		    (errno == ENOENT || errno == ECONNREFUSED)) {
238 			usleep(100);
239 			goto reconnect;
240 		}
241 		err(1, "connect: %s", sock);
242 	}
243 
244 	if (pledge("stdio", NULL) == -1)
245 		err(1, "pledge");
246 
247 	if (res->ibuf != NULL)
248 		ibuf = res->ibuf;
249 	else
250 		if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
251 			err(1, "malloc");
252 	imsg_init(ibuf, ctl_sock);
253 
254 	/* process user request */
255 	switch (res->action) {
256 	case RESETALL:
257 		v = RESET_ALL;
258 		break;
259 	case RESETCA:
260 		v = RESET_CA;
261 		break;
262 	case RESETPOLICY:
263 		v = RESET_POLICY;
264 		break;
265 	case RESETSA:
266 		v = RESET_SA;
267 		break;
268 	case RESETUSER:
269 		v = RESET_USER;
270 		break;
271 	case LOG_VERBOSE:
272 		v = 2;
273 		break;
274 	case LOG_BRIEF:
275 	default:
276 		v = 0;
277 		break;
278 	}
279 
280 	switch (res->action) {
281 	case NONE:
282 		usage();
283 		/* NOTREACHED */
284 		break;
285 	case RESETALL:
286 	case RESETCA:
287 	case RESETPOLICY:
288 	case RESETSA:
289 	case RESETUSER:
290 		imsg_compose(ibuf, IMSG_CTL_RESET, 0, 0, -1, &v, sizeof(v));
291 		printf("reset request sent.\n");
292 		break;
293 	case LOAD:
294 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1,
295 		    res->path, strlen(res->path));
296 		break;
297 	case RESET_ID:
298 		imsg_compose(ibuf, IMSG_CTL_RESET_ID, 0, 0, -1,
299 		    res->id, strlen(res->id));
300 		break;
301 	case SHOW_SA:
302 		imsg_compose(ibuf, IMSG_CTL_SHOW_SA, 0, 0, -1, NULL, 0);
303 		done = 0;
304 		break;
305 	case RELOAD:
306 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
307 		break;
308 	case MONITOR:
309 		imsg_compose(ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0);
310 		done = 0;
311 		break;
312 	case COUPLE:
313 		imsg_compose(ibuf, IMSG_CTL_COUPLE, 0, 0, -1, NULL, 0);
314 		break;
315 	case DECOUPLE:
316 		imsg_compose(ibuf, IMSG_CTL_DECOUPLE, 0, 0, -1, NULL, 0);
317 		break;
318 	case ACTIVE:
319 		imsg_compose(ibuf, IMSG_CTL_ACTIVE, 0, 0, -1, NULL, 0);
320 		break;
321 	case PASSIVE:
322 		imsg_compose(ibuf, IMSG_CTL_PASSIVE, 0, 0, -1, NULL, 0);
323 		break;
324 	case LOG_VERBOSE:
325 	case LOG_BRIEF:
326 		imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1, &v, sizeof(v));
327 		printf("logging request sent.\n");
328 		break;
329 	default:
330 		break;
331 	}
332 
333 	while (ibuf->w.queued)
334 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
335 			err(1, "write error");
336 
337 	while (!done) {
338 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
339 			errx(1, "imsg_read error");
340 		if (n == 0)
341 			errx(1, "pipe closed");
342 
343 		while (!done) {
344 			if ((n = imsg_get(ibuf, &imsg)) == -1)
345 				errx(1, "imsg_get error");
346 			if (n == 0)
347 				break;
348 			switch (res->action) {
349 			case MONITOR:
350 				done = monitor(&imsg);
351 				break;
352 			case SHOW_SA:
353 				done = show_string(&imsg);
354 				break;
355 			default:
356 				break;
357 			}
358 			imsg_free(&imsg);
359 		}
360 	}
361 	close(ctl_sock);
362 	free(ibuf);
363 
364 	return (0);
365 }
366 
367 struct imsgname *
368 monitor_lookup(uint8_t type)
369 {
370 	int i;
371 
372 	for (i = 0; imsgs[i].name != NULL; i++)
373 		if (imsgs[i].type == type)
374 			return (&imsgs[i]);
375 	return (&imsgunknown);
376 }
377 
378 int
379 monitor(struct imsg *imsg)
380 {
381 	time_t			 now;
382 	int			 done = 0;
383 	struct imsgname		*imn;
384 
385 	now = time(NULL);
386 
387 	imn = monitor_lookup(imsg->hdr.type);
388 	printf("%s: imsg type %u len %u peerid %u pid %d\n", imn->name,
389 	    imsg->hdr.type, imsg->hdr.len, imsg->hdr.peerid, imsg->hdr.pid);
390 	printf("\ttimestamp: %lld, %s", (long long)now, ctime(&now));
391 	if (imn->type == -1)
392 		done = 1;
393 	if (imn->func != NULL)
394 		(*imn->func)(imsg);
395 
396 	return (done);
397 }
398 
399 int
400 show_string(struct imsg *imsg)
401 {
402 	int	done = 0;
403 
404 	if (imsg->hdr.type != IMSG_CTL_SHOW_SA)
405 		return (done);
406 
407 	if (IMSG_DATA_SIZE(imsg) > 0)
408 		printf("%s", (char *)imsg->data);
409 	else
410 		done = 1;
411 
412 	return (done);
413 }
414