jcs's openbsd hax
openbsd
1/* $OpenBSD: parser.c,v 1.21 2022/09/19 20:54:02 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
38enum token_type {
39 NOTOKEN,
40 ENDTOKEN,
41 KEYWORD,
42 PATH,
43 CANAME,
44 PEER,
45 ADDRESS,
46 FQDN,
47 PASSWORD,
48 IKEID
49};
50
51struct token {
52 enum token_type type;
53 const char *keyword;
54 int value;
55 const struct token *next;
56};
57
58static const struct token t_main[];
59static const struct token t_reset[];
60static const struct token t_reset_id[];
61static const struct token t_log[];
62static const struct token t_load[];
63static const struct token t_ca[];
64static const struct token t_ca_pass[];
65static const struct token t_ca_pass_val[];
66static const struct token t_ca_export[];
67static const struct token t_ca_ex_peer[];
68static const struct token t_ca_ex_pass[];
69static const struct token t_ca_modifiers[];
70static const struct token t_ca_cert[];
71static const struct token t_ca_cert_extusage[];
72static const struct token t_ca_cert_modifiers[];
73static const struct token t_ca_key[];
74static const struct token t_ca_key_modifiers[];
75static const struct token t_ca_key_path[];
76static const struct token t_show[];
77static const struct token t_show_ca[];
78static const struct token t_show_ca_modifiers[];
79static const struct token t_show_ca_cert[];
80static const struct token t_opt_path[];
81
82static 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
97static const struct token t_log[] = {
98 { KEYWORD, "verbose", LOG_VERBOSE, NULL },
99 { KEYWORD, "brief", LOG_BRIEF, NULL },
100 { ENDTOKEN, "", NONE, NULL }
101};
102
103static 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
113static const struct token t_reset_id[] = {
114 { IKEID, "", NONE, NULL },
115 { ENDTOKEN, "", NONE, NULL }
116};
117
118static const struct token t_load[] = {
119 { PATH, "", NONE, NULL },
120 { ENDTOKEN, "", NONE, NULL }
121};
122
123static const struct token t_ca[] = {
124 { CANAME, "", NONE, t_ca_modifiers },
125 { ENDTOKEN, "", NONE, NULL },
126};
127
128static 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
138static const struct token t_ca_pass_val[] = {
139 { PASSWORD, "", NONE, NULL },
140 { ENDTOKEN, "", NONE, NULL }
141};
142
143static const struct token t_ca_pass[] = {
144 { NOTOKEN, "", NONE, NULL },
145 { KEYWORD, "password", NONE, t_ca_pass_val },
146 { ENDTOKEN, "", NONE, NULL }
147};
148
149static 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
156static const struct token t_ca_ex_peer[] = {
157 { PEER, "", NONE, t_ca_export },
158 { ENDTOKEN, "", NONE, NULL }
159};
160
161static const struct token t_ca_ex_pass[] = {
162 { PASSWORD, "", NONE, t_ca_export },
163 { ENDTOKEN, "", NONE, NULL }
164};
165
166static const struct token t_opt_path[] = {
167 { NOTOKEN, "", NONE, NULL },
168 { PATH, "", NONE, NULL },
169 { ENDTOKEN, "", NONE, NULL }
170};
171
172static 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
178static 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
187static 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
195static 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
201static 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
209static const struct token t_ca_key_path[] = {
210 { PATH, "", NONE, NULL },
211 { PATH, "", NONE, NULL }
212};
213
214static 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 { KEYWORD, "stats", SHOW_STATS, NULL },
219 { ENDTOKEN, "", NONE, NULL }
220};
221
222static const struct token t_show_ca[] = {
223 { CANAME, "", NONE, t_show_ca_modifiers },
224 { ENDTOKEN, "", NONE, NULL },
225};
226
227static const struct token t_show_ca_modifiers[] = {
228 { KEYWORD, "certificates", SHOW_CA_CERTIFICATES, t_show_ca_cert },
229 { ENDTOKEN, "", NONE, NULL }
230};
231
232static const struct token t_show_ca_cert[] = {
233 { NOTOKEN, "", NONE, NULL },
234 { ADDRESS, "", NONE, NULL },
235 { FQDN, "", NONE, NULL },
236 { ENDTOKEN, "", NONE, NULL }
237};
238
239static struct parse_result res;
240
241const struct token *match_token(char *, const struct token []);
242void show_valid_args(const struct token []);
243int parse_addr(const char *);
244
245struct parse_result *
246parse(int argc, char *argv[])
247{
248 const struct token *table = t_main;
249 const struct token *match;
250
251 bzero(&res, sizeof(res));
252
253 while (argc >= 0) {
254 if ((match = match_token(argv[0], table)) == NULL) {
255 fprintf(stderr, "valid commands/args:\n");
256 show_valid_args(table);
257 return (NULL);
258 }
259
260 argc--;
261 argv++;
262
263 if (match->type == NOTOKEN || match->next == NULL)
264 break;
265
266 table = match->next;
267 }
268
269 if (argc > 0) {
270 fprintf(stderr, "superfluous argument: %s\n", argv[0]);
271 return (NULL);
272 }
273
274 return (&res);
275}
276
277int
278parse_addr(const char *word)
279{
280 struct addrinfo hints, *r;
281
282 bzero(&hints, sizeof(hints));
283 hints.ai_socktype = SOCK_DGRAM; /* dummy */
284 hints.ai_family = PF_UNSPEC;
285 hints.ai_flags = AI_NUMERICHOST;
286 if (getaddrinfo(word, "0", &hints, &r) == 0) {
287 freeaddrinfo(r);
288 return (0);
289 }
290
291 return (1);
292}
293
294
295const struct token *
296match_token(char *word, const struct token table[])
297{
298 unsigned int i, match = 0;
299 const struct token *t = NULL;
300
301 for (i = 0; table[i].type != ENDTOKEN; i++) {
302 switch (table[i].type) {
303 case NOTOKEN:
304 if (word == NULL || strlen(word) == 0) {
305 match++;
306 t = &table[i];
307 }
308 break;
309 case KEYWORD:
310 if (word != NULL && strncmp(word, table[i].keyword,
311 strlen(word)) == 0) {
312 match++;
313 t = &table[i];
314 if (t->value)
315 res.action = t->value;
316 }
317 break;
318 case PATH:
319 if (!match && word != NULL && strlen(word) > 0) {
320 res.path = strdup(word);
321 match++;
322 t = &table[i];
323 }
324 break;
325 case CANAME:
326 if (!match && word != NULL && strlen(word) > 0) {
327 res.caname = strdup(word);
328 match++;
329 t = &table[i];
330 }
331 break;
332 case PEER:
333 if (!match && word != NULL && strlen(word) > 0) {
334 res.peer = strdup(word);
335 match++;
336 t = &table[i];
337 }
338 break;
339 case ADDRESS:
340 case FQDN:
341 if (!match && word != NULL && strlen(word) > 0) {
342 res.host = strdup(word);
343 if (parse_addr(word) == 0)
344 res.htype = HOST_IPADDR;
345 else
346 res.htype = HOST_FQDN;
347 match++;
348 t = &table[i];
349 }
350 break;
351 case PASSWORD:
352 if (!match && word != NULL && strlen(word) > 0) {
353 res.pass = strdup(word);
354 match++;
355 t = &table[i];
356 }
357 break;
358 case IKEID:
359 if (!match && word != NULL && strlen(word) > 0) {
360 res.id = strdup(word);
361 match++;
362 t = &table[i];
363 }
364 break;
365 case ENDTOKEN:
366 break;
367 }
368 }
369
370 if (match != 1) {
371 if (word == NULL)
372 fprintf(stderr, "missing argument:\n");
373 else if (match > 1)
374 fprintf(stderr, "ambiguous argument: %s\n", word);
375 else if (match < 1)
376 fprintf(stderr, "unknown argument: %s\n", word);
377 return (NULL);
378 }
379
380 return (t);
381}
382
383void
384show_valid_args(const struct token table[])
385{
386 int i;
387
388 for (i = 0; table[i].type != ENDTOKEN; i++) {
389 switch (table[i].type) {
390 case NOTOKEN:
391 fprintf(stderr, " <cr>\n");
392 break;
393 case KEYWORD:
394 fprintf(stderr, " %s\n", table[i].keyword);
395 break;
396 case PATH:
397 fprintf(stderr, " <path>\n");
398 break;
399 case CANAME:
400 fprintf(stderr, " <caname>\n");
401 break;
402 case PASSWORD:
403 fprintf(stderr, " <password>\n");
404 break;
405 case PEER:
406 fprintf(stderr, " <peer>\n");
407 break;
408 case ADDRESS:
409 fprintf(stderr, " <ipaddr>\n");
410 break;
411 case FQDN:
412 fprintf(stderr, " <fqdn>\n");
413 break;
414 case IKEID:
415 fprintf(stderr, " <ikeid>\n");
416 break;
417 case ENDTOKEN:
418 break;
419 }
420 }
421}