1*dbad4650Sderaadt /* $OpenBSD: parser.c,v 1.3 2015/01/19 01:48:57 deraadt Exp $ */
2363e4d4bSyasuoka
3363e4d4bSyasuoka /* This file is derived from OpenBSD:src/usr.sbin/ikectl/parser.c 1.9 */
4363e4d4bSyasuoka /*
5363e4d4bSyasuoka * Copyright (c) 2010 Reyk Floeter <reyk@vantronix.net>
6363e4d4bSyasuoka * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7363e4d4bSyasuoka * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8363e4d4bSyasuoka *
9363e4d4bSyasuoka * Permission to use, copy, modify, and distribute this software for any
10363e4d4bSyasuoka * purpose with or without fee is hereby granted, provided that the above
11363e4d4bSyasuoka * copyright notice and this permission notice appear in all copies.
12363e4d4bSyasuoka *
13363e4d4bSyasuoka * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14363e4d4bSyasuoka * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15363e4d4bSyasuoka * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16363e4d4bSyasuoka * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17363e4d4bSyasuoka * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18363e4d4bSyasuoka * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19363e4d4bSyasuoka * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20363e4d4bSyasuoka */
21363e4d4bSyasuoka
22363e4d4bSyasuoka #include <sys/socket.h>
23363e4d4bSyasuoka #include <netinet/in.h>
24363e4d4bSyasuoka #include <arpa/inet.h>
25363e4d4bSyasuoka
26363e4d4bSyasuoka #include <ctype.h>
27363e4d4bSyasuoka #include <errno.h>
28363e4d4bSyasuoka #include <limits.h>
29363e4d4bSyasuoka #include <stdio.h>
30363e4d4bSyasuoka #include <stdlib.h>
31363e4d4bSyasuoka #include <string.h>
32363e4d4bSyasuoka
33363e4d4bSyasuoka #include "parser.h"
34363e4d4bSyasuoka
35363e4d4bSyasuoka enum token_type {
36363e4d4bSyasuoka NOTOKEN,
37363e4d4bSyasuoka ENDTOKEN,
38363e4d4bSyasuoka KEYWORD,
39363e4d4bSyasuoka PPP_ID,
40363e4d4bSyasuoka ADDRESS,
41363e4d4bSyasuoka INTERFACE,
42363e4d4bSyasuoka PROTOCOL,
43363e4d4bSyasuoka REALM,
44363e4d4bSyasuoka USERNAME
45363e4d4bSyasuoka };
46363e4d4bSyasuoka
47363e4d4bSyasuoka struct token {
48363e4d4bSyasuoka enum token_type type;
49363e4d4bSyasuoka const char *keyword;
50363e4d4bSyasuoka int value;
51363e4d4bSyasuoka const struct token *next;
52363e4d4bSyasuoka };
53363e4d4bSyasuoka
54363e4d4bSyasuoka static struct parse_result res;
55363e4d4bSyasuoka
56363e4d4bSyasuoka static const struct token t_main[];
57363e4d4bSyasuoka static const struct token t_session[];
58363e4d4bSyasuoka static const struct token t_clear[];
5934682664Syasuoka static const struct token t_monitor[];
60363e4d4bSyasuoka static const struct token t_filter[];
61363e4d4bSyasuoka static const struct token t_ppp_id[];
62363e4d4bSyasuoka static const struct token t_address[];
63363e4d4bSyasuoka static const struct token t_interface[];
64363e4d4bSyasuoka static const struct token t_protocol[];
65363e4d4bSyasuoka static const struct token t_realm[];
66363e4d4bSyasuoka static const struct token t_username[];
67363e4d4bSyasuoka
68363e4d4bSyasuoka static const struct token t_main[] = {
69363e4d4bSyasuoka { KEYWORD, "session", NONE, t_session },
70363e4d4bSyasuoka { KEYWORD, "clear", NONE, t_clear },
7134682664Syasuoka { KEYWORD, "monitor", NONE, t_monitor },
72363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL }
73363e4d4bSyasuoka };
74363e4d4bSyasuoka
75363e4d4bSyasuoka static const struct token t_session[] = {
76363e4d4bSyasuoka { KEYWORD, "brief", SESSION_BRIEF, NULL },
77363e4d4bSyasuoka { KEYWORD, "packets", SESSION_PKTS, NULL },
78363e4d4bSyasuoka { KEYWORD, "all", SESSION_ALL, t_filter },
79363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL }
80363e4d4bSyasuoka };
81363e4d4bSyasuoka
82363e4d4bSyasuoka static const struct token t_clear[] = {
83363e4d4bSyasuoka { KEYWORD, "all", CLEAR_SESSION, NULL },
84363e4d4bSyasuoka { KEYWORD, "ppp-id", CLEAR_SESSION, t_ppp_id },
85363e4d4bSyasuoka { KEYWORD, "address", CLEAR_SESSION, t_address },
86363e4d4bSyasuoka { KEYWORD, "interface", CLEAR_SESSION, t_interface },
87363e4d4bSyasuoka { KEYWORD, "protocol", CLEAR_SESSION, t_protocol },
88363e4d4bSyasuoka { KEYWORD, "realm", CLEAR_SESSION, t_realm },
89363e4d4bSyasuoka { KEYWORD, "username", CLEAR_SESSION, t_username },
90363e4d4bSyasuoka { ENDTOKEN, "", CLEAR_SESSION, NULL }
91363e4d4bSyasuoka };
92363e4d4bSyasuoka
9334682664Syasuoka static const struct token t_monitor[] = {
9434682664Syasuoka { KEYWORD, "all", MONITOR_SESSION, NULL },
9534682664Syasuoka { KEYWORD, "ppp-id", MONITOR_SESSION, t_ppp_id },
9634682664Syasuoka { KEYWORD, "address", MONITOR_SESSION, t_address },
9734682664Syasuoka { KEYWORD, "interface", MONITOR_SESSION, t_interface },
9834682664Syasuoka { KEYWORD, "protocol", MONITOR_SESSION, t_protocol },
9934682664Syasuoka { KEYWORD, "realm", MONITOR_SESSION, t_realm },
10034682664Syasuoka { KEYWORD, "username", MONITOR_SESSION, t_username },
10134682664Syasuoka { ENDTOKEN, "", MONITOR_SESSION, NULL }
10234682664Syasuoka };
10334682664Syasuoka
104363e4d4bSyasuoka static const struct token t_filter[] = {
105363e4d4bSyasuoka { NOTOKEN, "", NONE, NULL },
106363e4d4bSyasuoka { KEYWORD, "ppp-id", NONE, t_ppp_id },
107363e4d4bSyasuoka { KEYWORD, "address", NONE, t_address },
108363e4d4bSyasuoka { KEYWORD, "interface", NONE, t_interface },
109363e4d4bSyasuoka { KEYWORD, "protocol", NONE, t_protocol },
110363e4d4bSyasuoka { KEYWORD, "realm", NONE, t_realm },
111363e4d4bSyasuoka { KEYWORD, "username", NONE, t_username },
112363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL }
113363e4d4bSyasuoka };
114363e4d4bSyasuoka
115363e4d4bSyasuoka static const struct token t_ppp_id[] = {
116363e4d4bSyasuoka { PPP_ID, "", NONE, t_filter },
117363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL }
118363e4d4bSyasuoka };
119363e4d4bSyasuoka static const struct token t_address[] = {
120363e4d4bSyasuoka { ADDRESS, "", NONE, t_filter },
121363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL }
122363e4d4bSyasuoka };
123363e4d4bSyasuoka static const struct token t_interface[] = {
124363e4d4bSyasuoka { INTERFACE, "", NONE, t_filter },
125363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL }
126363e4d4bSyasuoka };
127363e4d4bSyasuoka static const struct token t_protocol[] = {
128363e4d4bSyasuoka { PROTOCOL, "", NONE, t_filter },
129363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL }
130363e4d4bSyasuoka };
131363e4d4bSyasuoka static const struct token t_realm[] = {
132363e4d4bSyasuoka { REALM, "", NONE, t_filter },
133363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL }
134363e4d4bSyasuoka };
135363e4d4bSyasuoka static const struct token t_username[] = {
136363e4d4bSyasuoka { USERNAME, "", NONE, t_filter },
137363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL }
138363e4d4bSyasuoka };
139363e4d4bSyasuoka
140363e4d4bSyasuoka static const struct token *match_token(char *, const struct token []);
141363e4d4bSyasuoka static void show_valid_args(const struct token []);
142363e4d4bSyasuoka
143363e4d4bSyasuoka struct parse_result *
parse(int argc,char * argv[])144363e4d4bSyasuoka parse(int argc, char *argv[])
145363e4d4bSyasuoka {
146363e4d4bSyasuoka const struct token *table = t_main;
147363e4d4bSyasuoka const struct token *match;
148363e4d4bSyasuoka
149363e4d4bSyasuoka bzero(&res, sizeof(res));
150363e4d4bSyasuoka
151363e4d4bSyasuoka while (argc >= 0) {
152363e4d4bSyasuoka if ((match = match_token(argv[0], table)) == NULL) {
153363e4d4bSyasuoka fprintf(stderr, "valid commands/args:\n");
154363e4d4bSyasuoka show_valid_args(table);
155363e4d4bSyasuoka return (NULL);
156363e4d4bSyasuoka }
157363e4d4bSyasuoka
158363e4d4bSyasuoka argc--;
159363e4d4bSyasuoka argv++;
160363e4d4bSyasuoka
161363e4d4bSyasuoka if (match->type == NOTOKEN || match->next == NULL)
162363e4d4bSyasuoka break;
163363e4d4bSyasuoka
164363e4d4bSyasuoka table = match->next;
165363e4d4bSyasuoka }
166363e4d4bSyasuoka
167363e4d4bSyasuoka if (argc > 0) {
168363e4d4bSyasuoka fprintf(stderr, "superfluous argument: %s\n", argv[0]);
169363e4d4bSyasuoka return (NULL);
170363e4d4bSyasuoka }
171363e4d4bSyasuoka
172363e4d4bSyasuoka return (&res);
173363e4d4bSyasuoka }
174363e4d4bSyasuoka
175363e4d4bSyasuoka static const struct token *
match_token(char * word,const struct token table[])176363e4d4bSyasuoka match_token(char *word, const struct token table[])
177363e4d4bSyasuoka {
178363e4d4bSyasuoka u_int i, match = 0;
179363e4d4bSyasuoka unsigned long int ulval;
180363e4d4bSyasuoka const struct token *t = NULL;
181363e4d4bSyasuoka char *ep;
182363e4d4bSyasuoka
183363e4d4bSyasuoka for (i = 0; table[i].type != ENDTOKEN; i++) {
184363e4d4bSyasuoka switch (table[i].type) {
185363e4d4bSyasuoka case NOTOKEN:
186363e4d4bSyasuoka if (word == NULL || strlen(word) == 0) {
187363e4d4bSyasuoka match++;
188363e4d4bSyasuoka t = &table[i];
189363e4d4bSyasuoka }
190363e4d4bSyasuoka break;
191363e4d4bSyasuoka case KEYWORD:
192363e4d4bSyasuoka
193363e4d4bSyasuoka if (word != NULL && strncmp(word, table[i].keyword,
194363e4d4bSyasuoka strlen(word)) == 0) {
195363e4d4bSyasuoka match++;
196363e4d4bSyasuoka t = &table[i];
197363e4d4bSyasuoka if (t->value)
198363e4d4bSyasuoka res.action = t->value;
199363e4d4bSyasuoka }
200363e4d4bSyasuoka break;
201363e4d4bSyasuoka case PPP_ID:
202363e4d4bSyasuoka if (word == NULL)
203363e4d4bSyasuoka break;
204363e4d4bSyasuoka errno = 0;
205363e4d4bSyasuoka ulval = strtoul(word, &ep, 10);
206363e4d4bSyasuoka if (isdigit((unsigned char)*word) && *ep == '\0' &&
207363e4d4bSyasuoka !(errno == ERANGE && ulval == ULONG_MAX)) {
208363e4d4bSyasuoka res.ppp_id = ulval;
209363e4d4bSyasuoka res.has_ppp_id = 1;
210363e4d4bSyasuoka match++;
211363e4d4bSyasuoka t = &table[i];
212363e4d4bSyasuoka }
213363e4d4bSyasuoka break;
214363e4d4bSyasuoka case ADDRESS:
215363e4d4bSyasuoka {
216363e4d4bSyasuoka struct sockaddr_in sin4 = {
217363e4d4bSyasuoka .sin_family = AF_INET,
218363e4d4bSyasuoka .sin_len = sizeof(struct sockaddr_in)
219363e4d4bSyasuoka };
220363e4d4bSyasuoka struct sockaddr_in6 sin6 = {
221363e4d4bSyasuoka .sin6_family = AF_INET6,
222363e4d4bSyasuoka .sin6_len = sizeof(struct sockaddr_in6)
223363e4d4bSyasuoka };
224363e4d4bSyasuoka if (word == NULL)
225363e4d4bSyasuoka break;
226363e4d4bSyasuoka if (inet_pton(AF_INET, word, &sin4.sin_addr) == 1)
227363e4d4bSyasuoka memcpy(&res.address, &sin4, sin4.sin_len);
228363e4d4bSyasuoka else
229363e4d4bSyasuoka if (inet_pton(AF_INET6, word, &sin6.sin6_addr) == 1)
230363e4d4bSyasuoka memcpy(&res.address, &sin6, sin6.sin6_len);
231363e4d4bSyasuoka else
232363e4d4bSyasuoka break;
233363e4d4bSyasuoka match++;
234363e4d4bSyasuoka t = &table[i];
235363e4d4bSyasuoka }
236363e4d4bSyasuoka break;
237363e4d4bSyasuoka case INTERFACE:
238363e4d4bSyasuoka if (word == NULL)
239363e4d4bSyasuoka break;
240363e4d4bSyasuoka res.interface = word;
241363e4d4bSyasuoka match++;
242363e4d4bSyasuoka t = &table[i];
243363e4d4bSyasuoka break;
244363e4d4bSyasuoka case PROTOCOL:
245363e4d4bSyasuoka if (word == NULL)
246363e4d4bSyasuoka break;
247363e4d4bSyasuoka if ((res.protocol = parse_protocol(word)) ==
248363e4d4bSyasuoka PROTO_UNSPEC)
249363e4d4bSyasuoka break;
250363e4d4bSyasuoka match++;
251363e4d4bSyasuoka t = &table[i];
252363e4d4bSyasuoka break;
253363e4d4bSyasuoka case REALM:
254363e4d4bSyasuoka if (word == NULL)
255363e4d4bSyasuoka break;
256363e4d4bSyasuoka res.realm = word;
257363e4d4bSyasuoka match++;
258363e4d4bSyasuoka t = &table[i];
259363e4d4bSyasuoka break;
260363e4d4bSyasuoka case USERNAME:
261363e4d4bSyasuoka if (word == NULL)
262363e4d4bSyasuoka break;
263363e4d4bSyasuoka res.username = word;
264363e4d4bSyasuoka match++;
265363e4d4bSyasuoka t = &table[i];
266363e4d4bSyasuoka break;
267363e4d4bSyasuoka case ENDTOKEN:
268363e4d4bSyasuoka break;
269363e4d4bSyasuoka }
270363e4d4bSyasuoka }
271363e4d4bSyasuoka
272363e4d4bSyasuoka if (match != 1) {
273363e4d4bSyasuoka if (word == NULL)
274363e4d4bSyasuoka fprintf(stderr, "missing argument:\n");
275363e4d4bSyasuoka else if (match > 1)
276363e4d4bSyasuoka fprintf(stderr, "ambiguous argument: %s\n", word);
277363e4d4bSyasuoka else if (match < 1)
278363e4d4bSyasuoka fprintf(stderr, "unknown argument: %s\n", word);
279363e4d4bSyasuoka return (NULL);
280363e4d4bSyasuoka }
281363e4d4bSyasuoka
282363e4d4bSyasuoka return (t);
283363e4d4bSyasuoka }
284363e4d4bSyasuoka
285363e4d4bSyasuoka static void
show_valid_args(const struct token table[])286363e4d4bSyasuoka show_valid_args(const struct token table[])
287363e4d4bSyasuoka {
288363e4d4bSyasuoka int i;
289363e4d4bSyasuoka
290363e4d4bSyasuoka for (i = 0; table[i].type != ENDTOKEN; i++) {
291363e4d4bSyasuoka switch (table[i].type) {
292363e4d4bSyasuoka case NOTOKEN:
293363e4d4bSyasuoka fprintf(stderr, " <cr>\n");
294363e4d4bSyasuoka break;
295363e4d4bSyasuoka case KEYWORD:
296363e4d4bSyasuoka fprintf(stderr, " %s\n", table[i].keyword);
297363e4d4bSyasuoka break;
298363e4d4bSyasuoka case PPP_ID:
299363e4d4bSyasuoka fprintf(stderr, " <ppp-id>\n");
300363e4d4bSyasuoka break;
301363e4d4bSyasuoka case ADDRESS:
302363e4d4bSyasuoka fprintf(stderr, " <address>\n");
303363e4d4bSyasuoka break;
304363e4d4bSyasuoka case INTERFACE:
305363e4d4bSyasuoka fprintf(stderr, " <interface>\n");
306363e4d4bSyasuoka break;
307363e4d4bSyasuoka case PROTOCOL:
308363e4d4bSyasuoka fprintf(stderr, " [ pppoe | l2tp | pptp | sstp ]\n");
309363e4d4bSyasuoka break;
310363e4d4bSyasuoka case REALM:
311363e4d4bSyasuoka fprintf(stderr, " <realm>\n");
312363e4d4bSyasuoka break;
313363e4d4bSyasuoka case USERNAME:
314363e4d4bSyasuoka fprintf(stderr, " <username>\n");
315363e4d4bSyasuoka break;
316363e4d4bSyasuoka case ENDTOKEN:
317363e4d4bSyasuoka break;
318363e4d4bSyasuoka }
319363e4d4bSyasuoka }
320363e4d4bSyasuoka }
321363e4d4bSyasuoka
322363e4d4bSyasuoka enum protocol
parse_protocol(const char * str)323363e4d4bSyasuoka parse_protocol(const char *str)
324363e4d4bSyasuoka {
325363e4d4bSyasuoka return
326363e4d4bSyasuoka (strcasecmp(str, "PPTP" ) == 0)? PPTP :
327363e4d4bSyasuoka (strcasecmp(str, "L2TP" ) == 0)? L2TP :
328363e4d4bSyasuoka (strcasecmp(str, "PPPoE") == 0)? PPPOE :
329363e4d4bSyasuoka (strcasecmp(str, "SSTP" ) == 0)? SSTP : PROTO_UNSPEC;
330363e4d4bSyasuoka }
331363e4d4bSyasuoka
332