xref: /openbsd-src/usr.sbin/ikectl/parser.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: parser.c,v 1.12 2013/01/08 10:38:19 reyk 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/param.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/queue.h>
25 #include <sys/tree.h>
26 
27 #include <err.h>
28 #include <errno.h>
29 #include <limits.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <event.h>
34 #include <netdb.h>
35 
36 #include "iked.h"
37 #include "parser.h"
38 
39 enum token_type {
40 	NOTOKEN,
41 	ENDTOKEN,
42 	KEYWORD,
43 	PATH,
44 	CANAME,
45 	PEER,
46 	ADDRESS,
47 	FQDN,
48 	PASSWORD
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_log[];
61 static const struct token t_load[];
62 static const struct token t_ca[];
63 static const struct token t_ca_pass[];
64 static const struct token t_ca_pass_val[];
65 static const struct token t_ca_export[];
66 static const struct token t_ca_ex_peer[];
67 static const struct token t_ca_ex_pass[];
68 static const struct token t_ca_modifiers[];
69 static const struct token t_ca_cert[];
70 static const struct token t_ca_cert_extusage[];
71 static const struct token t_ca_cert_ex_peer[];
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 	{ ENDTOKEN,	"",		NONE,		NULL }
110 };
111 
112 static const struct token t_load[] = {
113 	{ PATH,		"",		NONE,		NULL },
114 	{ ENDTOKEN,	"",		NONE,		NULL }
115 };
116 
117 static const struct token t_ca[] = {
118 	{ CANAME,	"",		NONE,		t_ca_modifiers },
119 	{ ENDTOKEN,	"",		NONE,		NULL },
120 };
121 
122 static const struct token t_ca_modifiers[] = {
123 	{ KEYWORD,	"create",	CA_CREATE,	t_ca_pass },
124 	{ KEYWORD,	"delete",	CA_DELETE,	NULL },
125 	{ KEYWORD,	"install",	CA_INSTALL,	t_opt_path },
126 	{ KEYWORD,	"certificate",	CA_CERTIFICATE,	t_ca_cert },
127 	{ KEYWORD,	"key",		NONE,		t_ca_key },
128 	{ KEYWORD,	"export",	CA_EXPORT,	t_ca_export },
129 	{ ENDTOKEN,	"",		NONE,		NULL }
130 };
131 
132 static const struct token t_ca_pass_val[] = {
133 	{ PASSWORD,	"",		NONE,		NULL },
134 	{ ENDTOKEN,	"",		NONE,		NULL }
135 };
136 
137 static const struct token t_ca_pass[] = {
138 	{ NOTOKEN,	"",		NONE,		NULL },
139 	{ KEYWORD,	"password",	NONE,		t_ca_pass_val },
140 	{ ENDTOKEN,	"",		NONE,		NULL }
141 };
142 
143 static const struct token t_ca_export[] = {
144 	{ NOTOKEN,	"",		NONE,		NULL },
145 	{ KEYWORD,	"peer",		NONE,		t_ca_ex_peer },
146 	{ KEYWORD,	"password",	NONE,		t_ca_ex_pass },
147 	{ ENDTOKEN,	"",		NONE,		NULL }
148 };
149 
150 static const struct token t_ca_ex_peer[] = {
151 	{ PEER,		"",		NONE,		t_ca_export },
152 	{ ENDTOKEN,	"",		NONE,		NULL }
153 };
154 
155 static const struct token t_ca_ex_pass[] = {
156 	{ PASSWORD,	"",		NONE,		t_ca_export },
157 	{ ENDTOKEN,	"",		NONE,		NULL }
158 };
159 
160 static const struct token t_opt_path[] = {
161 	{ NOTOKEN,	"",		NONE,		NULL },
162 	{ PATH,		"",		NONE,		NULL },
163 	{ ENDTOKEN,	"",		NONE,		NULL }
164 };
165 
166 static const struct token t_ca_cert[] = {
167 	{ ADDRESS,	"",		NONE,		t_ca_cert_modifiers },
168 	{ FQDN,		"",		NONE,		t_ca_cert_modifiers },
169 	{ ENDTOKEN,	"",		NONE,		NULL }
170 };
171 
172 static const struct token t_ca_cert_modifiers[] = {
173 	{ KEYWORD,	"create",	CA_CERT_CREATE,		t_ca_cert_extusage },
174 	{ KEYWORD,	"delete",	CA_CERT_DELETE,		NULL },
175 	{ KEYWORD,	"install",	CA_CERT_INSTALL,	t_opt_path },
176 	{ KEYWORD,	"export",	CA_CERT_EXPORT,		t_ca_export },
177 	{ KEYWORD,	"revoke",	CA_CERT_REVOKE,		NULL },
178 	{ ENDTOKEN,	"",		NONE,			NULL }
179 };
180 
181 static const struct token t_ca_cert_extusage[] = {
182 	{ NOTOKEN,	"",		NONE,		NULL},
183 	{ KEYWORD,	"server",	CA_SERVER,	NULL },
184 	{ KEYWORD,	"client",	CA_CLIENT,	NULL },
185 	{ ENDTOKEN,	"",		NONE,		NULL },
186 };
187 
188 static const struct token t_ca_key[] = {
189 	{ ADDRESS,	"",		NONE,		t_ca_key_modifiers },
190 	{ FQDN,		"",		NONE,		t_ca_key_modifiers },
191 	{ ENDTOKEN,	"",		NONE,		NULL }
192 };
193 
194 static const struct token t_ca_key_modifiers[] = {
195 	{ KEYWORD,	"create",	CA_KEY_CREATE,		NULL },
196 	{ KEYWORD,	"delete",	CA_KEY_DELETE,		NULL },
197 	{ KEYWORD,	"install",	CA_KEY_INSTALL,		t_opt_path },
198 	{ KEYWORD,	"import",	CA_KEY_IMPORT,		t_ca_key_path },
199 	{ ENDTOKEN,	"",		NONE,			NULL }
200 };
201 
202 static const struct token t_ca_key_path[] = {
203 	{ PATH,		"",		NONE,		NULL },
204 	{ PATH,		"",		NONE,		NULL }
205 };
206 
207 static const struct token t_show[] = {
208 	{ KEYWORD,	"ca",		SHOW_CA,	t_show_ca },
209 	{ ENDTOKEN,	"",		NONE,		NULL }
210 };
211 
212 static const struct token t_show_ca[] = {
213 	{ CANAME,	"",		NONE,		t_show_ca_modifiers },
214 	{ ENDTOKEN,	"",		NONE,		NULL },
215 };
216 
217 static const struct token t_show_ca_modifiers[] = {
218 	{ KEYWORD,	"certificates",	SHOW_CA_CERTIFICATES,	t_show_ca_cert },
219 	{ ENDTOKEN,	"",		NONE,			NULL }
220 };
221 
222 static const struct token t_show_ca_cert[] = {
223 	{ NOTOKEN,	"",		NONE,		NULL },
224 	{ ADDRESS,	"",		NONE,		NULL },
225 	{ FQDN,		"",		NONE,		NULL },
226 	{ ENDTOKEN,	"",		NONE,		NULL }
227 };
228 
229 static struct parse_result	 res;
230 
231 const struct token		*match_token(char *, const struct token []);
232 void				 show_valid_args(const struct token []);
233 int				 parse_addr(const char *);
234 
235 struct parse_result *
236 parse(int argc, char *argv[])
237 {
238 	const struct token	*table = t_main;
239 	const struct token	*match;
240 
241 	bzero(&res, sizeof(res));
242 
243 	while (argc >= 0) {
244 		if ((match = match_token(argv[0], table)) == NULL) {
245 			fprintf(stderr, "valid commands/args:\n");
246 			show_valid_args(table);
247 			return (NULL);
248 		}
249 
250 		argc--;
251 		argv++;
252 
253 		if (match->type == NOTOKEN || match->next == NULL)
254 			break;
255 
256 		table = match->next;
257 	}
258 
259 	if (argc > 0) {
260 		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
261 		return (NULL);
262 	}
263 
264 	return (&res);
265 }
266 
267 int
268 parse_addr(const char *word)
269 {
270 	struct addrinfo hints, *r;
271 
272 	bzero(&hints, sizeof(hints));
273 	hints.ai_socktype = SOCK_DGRAM; /* dummy */
274 	hints.ai_family = PF_UNSPEC;
275 	hints.ai_flags = AI_NUMERICHOST;
276 	if (getaddrinfo(word, "0", &hints, &r) == 0) {
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 	u_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 				parse_addr(word);
332 				res.host = strdup(word);
333 				if (parse_addr(word) == 0)
334 					res.htype = HOST_IPADDR;
335 				else
336 					res.htype = HOST_FQDN;
337 				match++;
338 				t = &table[i];
339 			}
340 			break;
341 		case PASSWORD:
342 			if (!match && word != NULL && strlen(word) > 0) {
343 				res.pass = strdup(word);
344 				match++;
345 				t = &table[i];
346 			}
347 			break;
348 		case ENDTOKEN:
349 			break;
350 		}
351 	}
352 
353 	if (match != 1) {
354 		if (word == NULL)
355 			fprintf(stderr, "missing argument:\n");
356 		else if (match > 1)
357 			fprintf(stderr, "ambiguous argument: %s\n", word);
358 		else if (match < 1)
359 			fprintf(stderr, "unknown argument: %s\n", word);
360 		return (NULL);
361 	}
362 
363 	return (t);
364 }
365 
366 void
367 show_valid_args(const struct token table[])
368 {
369 	int	i;
370 
371 	for (i = 0; table[i].type != ENDTOKEN; i++) {
372 		switch (table[i].type) {
373 		case NOTOKEN:
374 			fprintf(stderr, "  <cr>\n");
375 			break;
376 		case KEYWORD:
377 			fprintf(stderr, "  %s\n", table[i].keyword);
378 			break;
379 		case PATH:
380 			fprintf(stderr, "  <path>\n");
381 			break;
382 		case CANAME:
383 			fprintf(stderr, "  <caname>\n");
384 			break;
385 		case PASSWORD:
386 			fprintf(stderr, "  <password>\n");
387 			break;
388 		case PEER:
389 			fprintf(stderr, "  <peer>\n");
390 			break;
391 		case ADDRESS:
392 			fprintf(stderr, "  <ipaddr>\n");
393 			break;
394 		case FQDN:
395 			fprintf(stderr, "  <fqdn>\n");
396 			break;
397 		case ENDTOKEN:
398 			break;
399 		}
400 	}
401 }
402