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
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 { KEYWORD, "stats", SHOW_STATS, NULL },
219 { ENDTOKEN, "", NONE, NULL }
220 };
221
222 static const struct token t_show_ca[] = {
223 { CANAME, "", NONE, t_show_ca_modifiers },
224 { ENDTOKEN, "", NONE, NULL },
225 };
226
227 static const struct token t_show_ca_modifiers[] = {
228 { KEYWORD, "certificates", SHOW_CA_CERTIFICATES, t_show_ca_cert },
229 { ENDTOKEN, "", NONE, NULL }
230 };
231
232 static 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
239 static struct parse_result res;
240
241 const struct token *match_token(char *, const struct token []);
242 void show_valid_args(const struct token []);
243 int parse_addr(const char *);
244
245 struct parse_result *
parse(int argc,char * argv[])246 parse(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
277 int
parse_addr(const char * word)278 parse_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
295 const struct token *
match_token(char * word,const struct token table[])296 match_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
383 void
show_valid_args(const struct token table[])384 show_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 }
422