xref: /openbsd/usr.sbin/ikectl/parser.c (revision 3cab2bb3)
1 /*	$OpenBSD: parser.c,v 1.19 2020/03/22 15:59:05 tobhe Exp $	*/
2 
3 /*
4  * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
5  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
6  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/queue.h>
24 #include <sys/tree.h>
25 
26 #include <err.h>
27 #include <errno.h>
28 #include <limits.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <event.h>
33 #include <netdb.h>
34 
35 #include "iked.h"
36 #include "parser.h"
37 
38 enum token_type {
39 	NOTOKEN,
40 	ENDTOKEN,
41 	KEYWORD,
42 	PATH,
43 	CANAME,
44 	PEER,
45 	ADDRESS,
46 	FQDN,
47 	PASSWORD,
48 	IKEID
49 };
50 
51 struct token {
52 	enum token_type		 type;
53 	const char		*keyword;
54 	int			 value;
55 	const struct token	*next;
56 };
57 
58 static const struct token t_main[];
59 static const struct token t_reset[];
60 static const struct token t_reset_id[];
61 static const struct token t_log[];
62 static const struct token t_load[];
63 static const struct token t_ca[];
64 static const struct token t_ca_pass[];
65 static const struct token t_ca_pass_val[];
66 static const struct token t_ca_export[];
67 static const struct token t_ca_ex_peer[];
68 static const struct token t_ca_ex_pass[];
69 static const struct token t_ca_modifiers[];
70 static const struct token t_ca_cert[];
71 static const struct token t_ca_cert_extusage[];
72 static const struct token t_ca_cert_modifiers[];
73 static const struct token t_ca_key[];
74 static const struct token t_ca_key_modifiers[];
75 static const struct token t_ca_key_path[];
76 static const struct token t_show[];
77 static const struct token t_show_ca[];
78 static const struct token t_show_ca_modifiers[];
79 static const struct token t_show_ca_cert[];
80 static const struct token t_opt_path[];
81 
82 static const struct token t_main[] = {
83 	{ KEYWORD,	"active",	ACTIVE,		NULL },
84 	{ KEYWORD,	"passive",	PASSIVE,	NULL },
85 	{ KEYWORD,	"couple",	COUPLE,		NULL },
86 	{ KEYWORD,	"decouple",	DECOUPLE,	NULL },
87 	{ KEYWORD,	"load",		LOAD,		t_load },
88 	{ KEYWORD,	"log",		NONE,		t_log },
89 	{ KEYWORD,	"monitor",	MONITOR,	NULL },
90 	{ KEYWORD,	"reload",	RELOAD,		NULL },
91 	{ KEYWORD,	"reset",	NONE,		t_reset },
92 	{ KEYWORD,	"show",		NONE,		t_show },
93 	{ KEYWORD,	"ca",		CA,		t_ca },
94 	{ ENDTOKEN,	"",		NONE,		NULL }
95 };
96 
97 static const struct token t_log[] = {
98 	{ KEYWORD,	"verbose",	LOG_VERBOSE,	NULL },
99 	{ KEYWORD,	"brief",	LOG_BRIEF,	NULL },
100 	{ ENDTOKEN,	"",		NONE,		NULL }
101 };
102 
103 static const struct token t_reset[] = {
104 	{ KEYWORD,	"all",		RESETALL,	NULL },
105 	{ KEYWORD,	"ca",		RESETCA,	NULL },
106 	{ KEYWORD,	"policy",	RESETPOLICY,	NULL },
107 	{ KEYWORD,	"sa",		RESETSA,	NULL },
108 	{ KEYWORD,	"user",		RESETUSER,	NULL },
109 	{ KEYWORD,	"id",		RESET_ID,	t_reset_id },
110 	{ ENDTOKEN,	"",		NONE,		NULL }
111 };
112 
113 static const struct token t_reset_id[] = {
114 	{ IKEID,	"",		NONE,		NULL },
115 	{ ENDTOKEN,	"",		NONE,		NULL }
116 };
117 
118 static const struct token t_load[] = {
119 	{ PATH,		"",		NONE,		NULL },
120 	{ ENDTOKEN,	"",		NONE,		NULL }
121 };
122 
123 static const struct token t_ca[] = {
124 	{ CANAME,	"",		NONE,		t_ca_modifiers },
125 	{ ENDTOKEN,	"",		NONE,		NULL },
126 };
127 
128 static const struct token t_ca_modifiers[] = {
129 	{ KEYWORD,	"create",	CA_CREATE,	t_ca_pass },
130 	{ KEYWORD,	"delete",	CA_DELETE,	NULL },
131 	{ KEYWORD,	"install",	CA_INSTALL,	t_opt_path },
132 	{ KEYWORD,	"certificate",	CA_CERTIFICATE,	t_ca_cert },
133 	{ KEYWORD,	"key",		NONE,		t_ca_key },
134 	{ KEYWORD,	"export",	CA_EXPORT,	t_ca_export },
135 	{ ENDTOKEN,	"",		NONE,		NULL }
136 };
137 
138 static const struct token t_ca_pass_val[] = {
139 	{ PASSWORD,	"",		NONE,		NULL },
140 	{ ENDTOKEN,	"",		NONE,		NULL }
141 };
142 
143 static const struct token t_ca_pass[] = {
144 	{ NOTOKEN,	"",		NONE,		NULL },
145 	{ KEYWORD,	"password",	NONE,		t_ca_pass_val },
146 	{ ENDTOKEN,	"",		NONE,		NULL }
147 };
148 
149 static const struct token t_ca_export[] = {
150 	{ NOTOKEN,	"",		NONE,		NULL },
151 	{ KEYWORD,	"peer",		NONE,		t_ca_ex_peer },
152 	{ KEYWORD,	"password",	NONE,		t_ca_ex_pass },
153 	{ ENDTOKEN,	"",		NONE,		NULL }
154 };
155 
156 static const struct token t_ca_ex_peer[] = {
157 	{ PEER,		"",		NONE,		t_ca_export },
158 	{ ENDTOKEN,	"",		NONE,		NULL }
159 };
160 
161 static const struct token t_ca_ex_pass[] = {
162 	{ PASSWORD,	"",		NONE,		t_ca_export },
163 	{ ENDTOKEN,	"",		NONE,		NULL }
164 };
165 
166 static const struct token t_opt_path[] = {
167 	{ NOTOKEN,	"",		NONE,		NULL },
168 	{ PATH,		"",		NONE,		NULL },
169 	{ ENDTOKEN,	"",		NONE,		NULL }
170 };
171 
172 static const struct token t_ca_cert[] = {
173 	{ ADDRESS,	"",		NONE,		t_ca_cert_modifiers },
174 	{ FQDN,		"",		NONE,		t_ca_cert_modifiers },
175 	{ ENDTOKEN,	"",		NONE,		NULL }
176 };
177 
178 static const struct token t_ca_cert_modifiers[] = {
179 	{ KEYWORD,	"create",	CA_CERT_CREATE,		t_ca_cert_extusage },
180 	{ KEYWORD,	"delete",	CA_CERT_DELETE,		NULL },
181 	{ KEYWORD,	"install",	CA_CERT_INSTALL,	t_opt_path },
182 	{ KEYWORD,	"export",	CA_CERT_EXPORT,		t_ca_export },
183 	{ KEYWORD,	"revoke",	CA_CERT_REVOKE,		NULL },
184 	{ ENDTOKEN,	"",		NONE,			NULL }
185 };
186 
187 static const struct token t_ca_cert_extusage[] = {
188 	{ NOTOKEN,	"",		NONE,		NULL},
189 	{ KEYWORD,	"server",	CA_SERVER,	NULL },
190 	{ KEYWORD,	"client",	CA_CLIENT,	NULL },
191 	{ KEYWORD,	"ocsp",		CA_OCSP,	NULL },
192 	{ ENDTOKEN,	"",		NONE,		NULL },
193 };
194 
195 static const struct token t_ca_key[] = {
196 	{ ADDRESS,	"",		NONE,		t_ca_key_modifiers },
197 	{ FQDN,		"",		NONE,		t_ca_key_modifiers },
198 	{ ENDTOKEN,	"",		NONE,		NULL }
199 };
200 
201 static const struct token t_ca_key_modifiers[] = {
202 	{ KEYWORD,	"create",	CA_KEY_CREATE,		NULL },
203 	{ KEYWORD,	"delete",	CA_KEY_DELETE,		NULL },
204 	{ KEYWORD,	"install",	CA_KEY_INSTALL,		t_opt_path },
205 	{ KEYWORD,	"import",	CA_KEY_IMPORT,		t_ca_key_path },
206 	{ ENDTOKEN,	"",		NONE,			NULL }
207 };
208 
209 static const struct token t_ca_key_path[] = {
210 	{ PATH,		"",		NONE,		NULL },
211 	{ PATH,		"",		NONE,		NULL }
212 };
213 
214 static const struct token t_show[] = {
215 	{ KEYWORD,	"ca",		SHOW_CA,	t_show_ca },
216 	{ KEYWORD,	"sa",		SHOW_SA,	NULL },
217 	{ ENDTOKEN,	"",		NONE,		NULL }
218 };
219 
220 static const struct token t_show_ca[] = {
221 	{ CANAME,	"",		NONE,		t_show_ca_modifiers },
222 	{ ENDTOKEN,	"",		NONE,		NULL },
223 };
224 
225 static const struct token t_show_ca_modifiers[] = {
226 	{ KEYWORD,	"certificates",	SHOW_CA_CERTIFICATES,	t_show_ca_cert },
227 	{ ENDTOKEN,	"",		NONE,			NULL }
228 };
229 
230 static const struct token t_show_ca_cert[] = {
231 	{ NOTOKEN,	"",		NONE,		NULL },
232 	{ ADDRESS,	"",		NONE,		NULL },
233 	{ FQDN,		"",		NONE,		NULL },
234 	{ ENDTOKEN,	"",		NONE,		NULL }
235 };
236 
237 static struct parse_result	 res;
238 
239 const struct token		*match_token(char *, const struct token []);
240 void				 show_valid_args(const struct token []);
241 int				 parse_addr(const char *);
242 
243 struct parse_result *
244 parse(int argc, char *argv[])
245 {
246 	const struct token	*table = t_main;
247 	const struct token	*match;
248 
249 	bzero(&res, sizeof(res));
250 
251 	while (argc >= 0) {
252 		if ((match = match_token(argv[0], table)) == NULL) {
253 			fprintf(stderr, "valid commands/args:\n");
254 			show_valid_args(table);
255 			return (NULL);
256 		}
257 
258 		argc--;
259 		argv++;
260 
261 		if (match->type == NOTOKEN || match->next == NULL)
262 			break;
263 
264 		table = match->next;
265 	}
266 
267 	if (argc > 0) {
268 		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
269 		return (NULL);
270 	}
271 
272 	return (&res);
273 }
274 
275 int
276 parse_addr(const char *word)
277 {
278 	struct addrinfo hints, *r;
279 
280 	bzero(&hints, sizeof(hints));
281 	hints.ai_socktype = SOCK_DGRAM; /* dummy */
282 	hints.ai_family = PF_UNSPEC;
283 	hints.ai_flags = AI_NUMERICHOST;
284 	if (getaddrinfo(word, "0", &hints, &r) == 0) {
285 		freeaddrinfo(r);
286 		return (0);
287 	}
288 
289 	return (1);
290 }
291 
292 
293 const struct token *
294 match_token(char *word, const struct token table[])
295 {
296 	unsigned int		 i, match = 0;
297 	const struct token	*t = NULL;
298 
299 	for (i = 0; table[i].type != ENDTOKEN; i++) {
300 		switch (table[i].type) {
301 		case NOTOKEN:
302 			if (word == NULL || strlen(word) == 0) {
303 				match++;
304 				t = &table[i];
305 			}
306 			break;
307 		case KEYWORD:
308 			if (word != NULL && strncmp(word, table[i].keyword,
309 			    strlen(word)) == 0) {
310 				match++;
311 				t = &table[i];
312 				if (t->value)
313 					res.action = t->value;
314 			}
315 			break;
316 		case PATH:
317 			if (!match && word != NULL && strlen(word) > 0) {
318 				res.path = strdup(word);
319 				match++;
320 				t = &table[i];
321 			}
322 			break;
323 		case CANAME:
324 			if (!match && word != NULL && strlen(word) > 0) {
325 				res.caname = strdup(word);
326 				match++;
327 				t = &table[i];
328 			}
329 			break;
330 		case PEER:
331 			if (!match && word != NULL && strlen(word) > 0) {
332 				res.peer = strdup(word);
333 				match++;
334 				t = &table[i];
335 			}
336 			break;
337 		case ADDRESS:
338 		case FQDN:
339 			if (!match && word != NULL && strlen(word) > 0) {
340 				res.host = strdup(word);
341 				if (parse_addr(word) == 0)
342 					res.htype = HOST_IPADDR;
343 				else
344 					res.htype = HOST_FQDN;
345 				match++;
346 				t = &table[i];
347 			}
348 			break;
349 		case PASSWORD:
350 			if (!match && word != NULL && strlen(word) > 0) {
351 				res.pass = strdup(word);
352 				match++;
353 				t = &table[i];
354 			}
355 			break;
356 		case IKEID:
357 			if (!match && word != NULL && strlen(word) > 0) {
358 				res.id = strdup(word);
359 				match++;
360 				t = &table[i];
361 			}
362 			break;
363 		case ENDTOKEN:
364 			break;
365 		}
366 	}
367 
368 	if (match != 1) {
369 		if (word == NULL)
370 			fprintf(stderr, "missing argument:\n");
371 		else if (match > 1)
372 			fprintf(stderr, "ambiguous argument: %s\n", word);
373 		else if (match < 1)
374 			fprintf(stderr, "unknown argument: %s\n", word);
375 		return (NULL);
376 	}
377 
378 	return (t);
379 }
380 
381 void
382 show_valid_args(const struct token table[])
383 {
384 	int	i;
385 
386 	for (i = 0; table[i].type != ENDTOKEN; i++) {
387 		switch (table[i].type) {
388 		case NOTOKEN:
389 			fprintf(stderr, "  <cr>\n");
390 			break;
391 		case KEYWORD:
392 			fprintf(stderr, "  %s\n", table[i].keyword);
393 			break;
394 		case PATH:
395 			fprintf(stderr, "  <path>\n");
396 			break;
397 		case CANAME:
398 			fprintf(stderr, "  <caname>\n");
399 			break;
400 		case PASSWORD:
401 			fprintf(stderr, "  <password>\n");
402 			break;
403 		case PEER:
404 			fprintf(stderr, "  <peer>\n");
405 			break;
406 		case ADDRESS:
407 			fprintf(stderr, "  <ipaddr>\n");
408 			break;
409 		case FQDN:
410 			fprintf(stderr, "  <fqdn>\n");
411 			break;
412 		case IKEID:
413 			fprintf(stderr, "  <ikeid>\n");
414 			break;
415 		case ENDTOKEN:
416 			break;
417 		}
418 	}
419 }
420