xref: /openbsd-src/usr.sbin/ikectl/parser.c (revision d89ec533011f513df1010f142a111086a0785f09)
1 /*	$OpenBSD: parser.c,v 1.20 2021/11/21 22:44:08 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 	{ KEYWORD,	"certstore",	SHOW_CERTSTORE,NULL },
218 	{ ENDTOKEN,	"",		NONE,		NULL }
219 };
220 
221 static const struct token t_show_ca[] = {
222 	{ CANAME,	"",		NONE,		t_show_ca_modifiers },
223 	{ ENDTOKEN,	"",		NONE,		NULL },
224 };
225 
226 static const struct token t_show_ca_modifiers[] = {
227 	{ KEYWORD,	"certificates",	SHOW_CA_CERTIFICATES,	t_show_ca_cert },
228 	{ ENDTOKEN,	"",		NONE,			NULL }
229 };
230 
231 static const struct token t_show_ca_cert[] = {
232 	{ NOTOKEN,	"",		NONE,		NULL },
233 	{ ADDRESS,	"",		NONE,		NULL },
234 	{ FQDN,		"",		NONE,		NULL },
235 	{ ENDTOKEN,	"",		NONE,		NULL }
236 };
237 
238 static struct parse_result	 res;
239 
240 const struct token		*match_token(char *, const struct token []);
241 void				 show_valid_args(const struct token []);
242 int				 parse_addr(const char *);
243 
244 struct parse_result *
245 parse(int argc, char *argv[])
246 {
247 	const struct token	*table = t_main;
248 	const struct token	*match;
249 
250 	bzero(&res, sizeof(res));
251 
252 	while (argc >= 0) {
253 		if ((match = match_token(argv[0], table)) == NULL) {
254 			fprintf(stderr, "valid commands/args:\n");
255 			show_valid_args(table);
256 			return (NULL);
257 		}
258 
259 		argc--;
260 		argv++;
261 
262 		if (match->type == NOTOKEN || match->next == NULL)
263 			break;
264 
265 		table = match->next;
266 	}
267 
268 	if (argc > 0) {
269 		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
270 		return (NULL);
271 	}
272 
273 	return (&res);
274 }
275 
276 int
277 parse_addr(const char *word)
278 {
279 	struct addrinfo hints, *r;
280 
281 	bzero(&hints, sizeof(hints));
282 	hints.ai_socktype = SOCK_DGRAM; /* dummy */
283 	hints.ai_family = PF_UNSPEC;
284 	hints.ai_flags = AI_NUMERICHOST;
285 	if (getaddrinfo(word, "0", &hints, &r) == 0) {
286 		freeaddrinfo(r);
287 		return (0);
288 	}
289 
290 	return (1);
291 }
292 
293 
294 const struct token *
295 match_token(char *word, const struct token table[])
296 {
297 	unsigned int		 i, match = 0;
298 	const struct token	*t = NULL;
299 
300 	for (i = 0; table[i].type != ENDTOKEN; i++) {
301 		switch (table[i].type) {
302 		case NOTOKEN:
303 			if (word == NULL || strlen(word) == 0) {
304 				match++;
305 				t = &table[i];
306 			}
307 			break;
308 		case KEYWORD:
309 			if (word != NULL && strncmp(word, table[i].keyword,
310 			    strlen(word)) == 0) {
311 				match++;
312 				t = &table[i];
313 				if (t->value)
314 					res.action = t->value;
315 			}
316 			break;
317 		case PATH:
318 			if (!match && word != NULL && strlen(word) > 0) {
319 				res.path = strdup(word);
320 				match++;
321 				t = &table[i];
322 			}
323 			break;
324 		case CANAME:
325 			if (!match && word != NULL && strlen(word) > 0) {
326 				res.caname = strdup(word);
327 				match++;
328 				t = &table[i];
329 			}
330 			break;
331 		case PEER:
332 			if (!match && word != NULL && strlen(word) > 0) {
333 				res.peer = strdup(word);
334 				match++;
335 				t = &table[i];
336 			}
337 			break;
338 		case ADDRESS:
339 		case FQDN:
340 			if (!match && word != NULL && strlen(word) > 0) {
341 				res.host = strdup(word);
342 				if (parse_addr(word) == 0)
343 					res.htype = HOST_IPADDR;
344 				else
345 					res.htype = HOST_FQDN;
346 				match++;
347 				t = &table[i];
348 			}
349 			break;
350 		case PASSWORD:
351 			if (!match && word != NULL && strlen(word) > 0) {
352 				res.pass = strdup(word);
353 				match++;
354 				t = &table[i];
355 			}
356 			break;
357 		case IKEID:
358 			if (!match && word != NULL && strlen(word) > 0) {
359 				res.id = strdup(word);
360 				match++;
361 				t = &table[i];
362 			}
363 			break;
364 		case ENDTOKEN:
365 			break;
366 		}
367 	}
368 
369 	if (match != 1) {
370 		if (word == NULL)
371 			fprintf(stderr, "missing argument:\n");
372 		else if (match > 1)
373 			fprintf(stderr, "ambiguous argument: %s\n", word);
374 		else if (match < 1)
375 			fprintf(stderr, "unknown argument: %s\n", word);
376 		return (NULL);
377 	}
378 
379 	return (t);
380 }
381 
382 void
383 show_valid_args(const struct token table[])
384 {
385 	int	i;
386 
387 	for (i = 0; table[i].type != ENDTOKEN; i++) {
388 		switch (table[i].type) {
389 		case NOTOKEN:
390 			fprintf(stderr, "  <cr>\n");
391 			break;
392 		case KEYWORD:
393 			fprintf(stderr, "  %s\n", table[i].keyword);
394 			break;
395 		case PATH:
396 			fprintf(stderr, "  <path>\n");
397 			break;
398 		case CANAME:
399 			fprintf(stderr, "  <caname>\n");
400 			break;
401 		case PASSWORD:
402 			fprintf(stderr, "  <password>\n");
403 			break;
404 		case PEER:
405 			fprintf(stderr, "  <peer>\n");
406 			break;
407 		case ADDRESS:
408 			fprintf(stderr, "  <ipaddr>\n");
409 			break;
410 		case FQDN:
411 			fprintf(stderr, "  <fqdn>\n");
412 			break;
413 		case IKEID:
414 			fprintf(stderr, "  <ikeid>\n");
415 			break;
416 		case ENDTOKEN:
417 			break;
418 		}
419 	}
420 }
421