xref: /openbsd-src/usr.sbin/ikectl/parser.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: parser.c,v 1.17 2018/06/18 10:20:19 benno 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 };
49 
50 struct token {
51 	enum token_type		 type;
52 	const char		*keyword;
53 	int			 value;
54 	const struct token	*next;
55 };
56 
57 static const struct token t_main[];
58 static const struct token t_reset[];
59 static const struct token t_log[];
60 static const struct token t_load[];
61 static const struct token t_ca[];
62 static const struct token t_ca_pass[];
63 static const struct token t_ca_pass_val[];
64 static const struct token t_ca_export[];
65 static const struct token t_ca_ex_peer[];
66 static const struct token t_ca_ex_pass[];
67 static const struct token t_ca_modifiers[];
68 static const struct token t_ca_cert[];
69 static const struct token t_ca_cert_extusage[];
70 static const struct token t_ca_cert_modifiers[];
71 static const struct token t_ca_key[];
72 static const struct token t_ca_key_modifiers[];
73 static const struct token t_ca_key_path[];
74 static const struct token t_show[];
75 static const struct token t_show_ca[];
76 static const struct token t_show_ca_modifiers[];
77 static const struct token t_show_ca_cert[];
78 static const struct token t_opt_path[];
79 
80 static const struct token t_main[] = {
81 	{ KEYWORD,	"active",	ACTIVE,		NULL },
82 	{ KEYWORD,	"passive",	PASSIVE,	NULL },
83 	{ KEYWORD,	"couple",	COUPLE,		NULL },
84 	{ KEYWORD,	"decouple",	DECOUPLE,	NULL },
85 	{ KEYWORD,	"load",		LOAD,		t_load },
86 	{ KEYWORD,	"log",		NONE,		t_log },
87 	{ KEYWORD,	"monitor",	MONITOR,	NULL },
88 	{ KEYWORD,	"reload",	RELOAD,		NULL },
89 	{ KEYWORD,	"reset",	NONE,		t_reset },
90 	{ KEYWORD,	"show",		NONE,		t_show },
91 	{ KEYWORD,	"ca",		CA,		t_ca },
92 	{ ENDTOKEN,	"",		NONE,		NULL }
93 };
94 
95 static const struct token t_log[] = {
96 	{ KEYWORD,	"verbose",	LOG_VERBOSE,	NULL },
97 	{ KEYWORD,	"brief",	LOG_BRIEF,	NULL },
98 	{ ENDTOKEN,	"",		NONE,		NULL }
99 };
100 
101 static const struct token t_reset[] = {
102 	{ KEYWORD,	"all",		RESETALL,	NULL },
103 	{ KEYWORD,	"ca",		RESETCA,	NULL },
104 	{ KEYWORD,	"policy",	RESETPOLICY,	NULL },
105 	{ KEYWORD,	"sa",		RESETSA,	NULL },
106 	{ KEYWORD,	"user",		RESETUSER,	NULL },
107 	{ ENDTOKEN,	"",		NONE,		NULL }
108 };
109 
110 static const struct token t_load[] = {
111 	{ PATH,		"",		NONE,		NULL },
112 	{ ENDTOKEN,	"",		NONE,		NULL }
113 };
114 
115 static const struct token t_ca[] = {
116 	{ CANAME,	"",		NONE,		t_ca_modifiers },
117 	{ ENDTOKEN,	"",		NONE,		NULL },
118 };
119 
120 static const struct token t_ca_modifiers[] = {
121 	{ KEYWORD,	"create",	CA_CREATE,	t_ca_pass },
122 	{ KEYWORD,	"delete",	CA_DELETE,	NULL },
123 	{ KEYWORD,	"install",	CA_INSTALL,	t_opt_path },
124 	{ KEYWORD,	"certificate",	CA_CERTIFICATE,	t_ca_cert },
125 	{ KEYWORD,	"key",		NONE,		t_ca_key },
126 	{ KEYWORD,	"export",	CA_EXPORT,	t_ca_export },
127 	{ ENDTOKEN,	"",		NONE,		NULL }
128 };
129 
130 static const struct token t_ca_pass_val[] = {
131 	{ PASSWORD,	"",		NONE,		NULL },
132 	{ ENDTOKEN,	"",		NONE,		NULL }
133 };
134 
135 static const struct token t_ca_pass[] = {
136 	{ NOTOKEN,	"",		NONE,		NULL },
137 	{ KEYWORD,	"password",	NONE,		t_ca_pass_val },
138 	{ ENDTOKEN,	"",		NONE,		NULL }
139 };
140 
141 static const struct token t_ca_export[] = {
142 	{ NOTOKEN,	"",		NONE,		NULL },
143 	{ KEYWORD,	"peer",		NONE,		t_ca_ex_peer },
144 	{ KEYWORD,	"password",	NONE,		t_ca_ex_pass },
145 	{ ENDTOKEN,	"",		NONE,		NULL }
146 };
147 
148 static const struct token t_ca_ex_peer[] = {
149 	{ PEER,		"",		NONE,		t_ca_export },
150 	{ ENDTOKEN,	"",		NONE,		NULL }
151 };
152 
153 static const struct token t_ca_ex_pass[] = {
154 	{ PASSWORD,	"",		NONE,		t_ca_export },
155 	{ ENDTOKEN,	"",		NONE,		NULL }
156 };
157 
158 static const struct token t_opt_path[] = {
159 	{ NOTOKEN,	"",		NONE,		NULL },
160 	{ PATH,		"",		NONE,		NULL },
161 	{ ENDTOKEN,	"",		NONE,		NULL }
162 };
163 
164 static const struct token t_ca_cert[] = {
165 	{ ADDRESS,	"",		NONE,		t_ca_cert_modifiers },
166 	{ FQDN,		"",		NONE,		t_ca_cert_modifiers },
167 	{ ENDTOKEN,	"",		NONE,		NULL }
168 };
169 
170 static const struct token t_ca_cert_modifiers[] = {
171 	{ KEYWORD,	"create",	CA_CERT_CREATE,		t_ca_cert_extusage },
172 	{ KEYWORD,	"delete",	CA_CERT_DELETE,		NULL },
173 	{ KEYWORD,	"install",	CA_CERT_INSTALL,	t_opt_path },
174 	{ KEYWORD,	"export",	CA_CERT_EXPORT,		t_ca_export },
175 	{ KEYWORD,	"revoke",	CA_CERT_REVOKE,		NULL },
176 	{ ENDTOKEN,	"",		NONE,			NULL }
177 };
178 
179 static const struct token t_ca_cert_extusage[] = {
180 	{ NOTOKEN,	"",		NONE,		NULL},
181 	{ KEYWORD,	"server",	CA_SERVER,	NULL },
182 	{ KEYWORD,	"client",	CA_CLIENT,	NULL },
183 	{ KEYWORD,	"ocsp",		CA_OCSP,	NULL },
184 	{ ENDTOKEN,	"",		NONE,		NULL },
185 };
186 
187 static const struct token t_ca_key[] = {
188 	{ ADDRESS,	"",		NONE,		t_ca_key_modifiers },
189 	{ FQDN,		"",		NONE,		t_ca_key_modifiers },
190 	{ ENDTOKEN,	"",		NONE,		NULL }
191 };
192 
193 static const struct token t_ca_key_modifiers[] = {
194 	{ KEYWORD,	"create",	CA_KEY_CREATE,		NULL },
195 	{ KEYWORD,	"delete",	CA_KEY_DELETE,		NULL },
196 	{ KEYWORD,	"install",	CA_KEY_INSTALL,		t_opt_path },
197 	{ KEYWORD,	"import",	CA_KEY_IMPORT,		t_ca_key_path },
198 	{ ENDTOKEN,	"",		NONE,			NULL }
199 };
200 
201 static const struct token t_ca_key_path[] = {
202 	{ PATH,		"",		NONE,		NULL },
203 	{ PATH,		"",		NONE,		NULL }
204 };
205 
206 static const struct token t_show[] = {
207 	{ KEYWORD,	"ca",		SHOW_CA,	t_show_ca },
208 	{ ENDTOKEN,	"",		NONE,		NULL }
209 };
210 
211 static const struct token t_show_ca[] = {
212 	{ CANAME,	"",		NONE,		t_show_ca_modifiers },
213 	{ ENDTOKEN,	"",		NONE,		NULL },
214 };
215 
216 static const struct token t_show_ca_modifiers[] = {
217 	{ KEYWORD,	"certificates",	SHOW_CA_CERTIFICATES,	t_show_ca_cert },
218 	{ ENDTOKEN,	"",		NONE,			NULL }
219 };
220 
221 static const struct token t_show_ca_cert[] = {
222 	{ NOTOKEN,	"",		NONE,		NULL },
223 	{ ADDRESS,	"",		NONE,		NULL },
224 	{ FQDN,		"",		NONE,		NULL },
225 	{ ENDTOKEN,	"",		NONE,		NULL }
226 };
227 
228 static struct parse_result	 res;
229 
230 const struct token		*match_token(char *, const struct token []);
231 void				 show_valid_args(const struct token []);
232 int				 parse_addr(const char *);
233 
234 struct parse_result *
235 parse(int argc, char *argv[])
236 {
237 	const struct token	*table = t_main;
238 	const struct token	*match;
239 
240 	bzero(&res, sizeof(res));
241 
242 	while (argc >= 0) {
243 		if ((match = match_token(argv[0], table)) == NULL) {
244 			fprintf(stderr, "valid commands/args:\n");
245 			show_valid_args(table);
246 			return (NULL);
247 		}
248 
249 		argc--;
250 		argv++;
251 
252 		if (match->type == NOTOKEN || match->next == NULL)
253 			break;
254 
255 		table = match->next;
256 	}
257 
258 	if (argc > 0) {
259 		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
260 		return (NULL);
261 	}
262 
263 	return (&res);
264 }
265 
266 int
267 parse_addr(const char *word)
268 {
269 	struct addrinfo hints, *r;
270 
271 	bzero(&hints, sizeof(hints));
272 	hints.ai_socktype = SOCK_DGRAM; /* dummy */
273 	hints.ai_family = PF_UNSPEC;
274 	hints.ai_flags = AI_NUMERICHOST;
275 	if (getaddrinfo(word, "0", &hints, &r) == 0) {
276 		freeaddrinfo(r);
277 		return (0);
278 	}
279 
280 	return (1);
281 }
282 
283 
284 const struct token *
285 match_token(char *word, const struct token table[])
286 {
287 	unsigned int		 i, match = 0;
288 	const struct token	*t = NULL;
289 
290 	for (i = 0; table[i].type != ENDTOKEN; i++) {
291 		switch (table[i].type) {
292 		case NOTOKEN:
293 			if (word == NULL || strlen(word) == 0) {
294 				match++;
295 				t = &table[i];
296 			}
297 			break;
298 		case KEYWORD:
299 			if (word != NULL && strncmp(word, table[i].keyword,
300 			    strlen(word)) == 0) {
301 				match++;
302 				t = &table[i];
303 				if (t->value)
304 					res.action = t->value;
305 			}
306 			break;
307 		case PATH:
308 			if (!match && word != NULL && strlen(word) > 0) {
309 				res.path = strdup(word);
310 				match++;
311 				t = &table[i];
312 			}
313 			break;
314 		case CANAME:
315 			if (!match && word != NULL && strlen(word) > 0) {
316 				res.caname = strdup(word);
317 				match++;
318 				t = &table[i];
319 			}
320 			break;
321 		case PEER:
322 			if (!match && word != NULL && strlen(word) > 0) {
323 				res.peer = strdup(word);
324 				match++;
325 				t = &table[i];
326 			}
327 			break;
328 		case ADDRESS:
329 		case FQDN:
330 			if (!match && word != NULL && strlen(word) > 0) {
331 				res.host = strdup(word);
332 				if (parse_addr(word) == 0)
333 					res.htype = HOST_IPADDR;
334 				else
335 					res.htype = HOST_FQDN;
336 				match++;
337 				t = &table[i];
338 			}
339 			break;
340 		case PASSWORD:
341 			if (!match && word != NULL && strlen(word) > 0) {
342 				res.pass = strdup(word);
343 				match++;
344 				t = &table[i];
345 			}
346 			break;
347 		case ENDTOKEN:
348 			break;
349 		}
350 	}
351 
352 	if (match != 1) {
353 		if (word == NULL)
354 			fprintf(stderr, "missing argument:\n");
355 		else if (match > 1)
356 			fprintf(stderr, "ambiguous argument: %s\n", word);
357 		else if (match < 1)
358 			fprintf(stderr, "unknown argument: %s\n", word);
359 		return (NULL);
360 	}
361 
362 	return (t);
363 }
364 
365 void
366 show_valid_args(const struct token table[])
367 {
368 	int	i;
369 
370 	for (i = 0; table[i].type != ENDTOKEN; i++) {
371 		switch (table[i].type) {
372 		case NOTOKEN:
373 			fprintf(stderr, "  <cr>\n");
374 			break;
375 		case KEYWORD:
376 			fprintf(stderr, "  %s\n", table[i].keyword);
377 			break;
378 		case PATH:
379 			fprintf(stderr, "  <path>\n");
380 			break;
381 		case CANAME:
382 			fprintf(stderr, "  <caname>\n");
383 			break;
384 		case PASSWORD:
385 			fprintf(stderr, "  <password>\n");
386 			break;
387 		case PEER:
388 			fprintf(stderr, "  <peer>\n");
389 			break;
390 		case ADDRESS:
391 			fprintf(stderr, "  <ipaddr>\n");
392 			break;
393 		case FQDN:
394 			fprintf(stderr, "  <fqdn>\n");
395 			break;
396 		case ENDTOKEN:
397 			break;
398 		}
399 	}
400 }
401