xref: /openbsd/usr.sbin/npppctl/parser.c (revision dbad4650)
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