xref: /openbsd/usr.sbin/npppctl/parser.c (revision 363e4d4b)
1*363e4d4bSyasuoka /*	$OpenBSD: parser.c,v 1.1 2012/01/18 03:13:04 yasuoka Exp $	*/
2*363e4d4bSyasuoka 
3*363e4d4bSyasuoka /* This file is derived from OpenBSD:src/usr.sbin/ikectl/parser.c 1.9 */
4*363e4d4bSyasuoka /*
5*363e4d4bSyasuoka  * Copyright (c) 2010 Reyk Floeter <reyk@vantronix.net>
6*363e4d4bSyasuoka  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7*363e4d4bSyasuoka  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8*363e4d4bSyasuoka  *
9*363e4d4bSyasuoka  * Permission to use, copy, modify, and distribute this software for any
10*363e4d4bSyasuoka  * purpose with or without fee is hereby granted, provided that the above
11*363e4d4bSyasuoka  * copyright notice and this permission notice appear in all copies.
12*363e4d4bSyasuoka  *
13*363e4d4bSyasuoka  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14*363e4d4bSyasuoka  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15*363e4d4bSyasuoka  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16*363e4d4bSyasuoka  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17*363e4d4bSyasuoka  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18*363e4d4bSyasuoka  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19*363e4d4bSyasuoka  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20*363e4d4bSyasuoka  */
21*363e4d4bSyasuoka 
22*363e4d4bSyasuoka #include <sys/param.h>
23*363e4d4bSyasuoka #include <sys/socket.h>
24*363e4d4bSyasuoka #include <netinet/in.h>
25*363e4d4bSyasuoka #include <arpa/inet.h>
26*363e4d4bSyasuoka 
27*363e4d4bSyasuoka #include <ctype.h>
28*363e4d4bSyasuoka #include <errno.h>
29*363e4d4bSyasuoka #include <limits.h>
30*363e4d4bSyasuoka #include <stdio.h>
31*363e4d4bSyasuoka #include <stdlib.h>
32*363e4d4bSyasuoka #include <string.h>
33*363e4d4bSyasuoka 
34*363e4d4bSyasuoka #include "parser.h"
35*363e4d4bSyasuoka 
36*363e4d4bSyasuoka enum token_type {
37*363e4d4bSyasuoka 	NOTOKEN,
38*363e4d4bSyasuoka 	ENDTOKEN,
39*363e4d4bSyasuoka 	KEYWORD,
40*363e4d4bSyasuoka 	PPP_ID,
41*363e4d4bSyasuoka 	ADDRESS,
42*363e4d4bSyasuoka 	INTERFACE,
43*363e4d4bSyasuoka 	PROTOCOL,
44*363e4d4bSyasuoka 	REALM,
45*363e4d4bSyasuoka 	USERNAME
46*363e4d4bSyasuoka };
47*363e4d4bSyasuoka 
48*363e4d4bSyasuoka struct token {
49*363e4d4bSyasuoka 	enum token_type		 type;
50*363e4d4bSyasuoka 	const char		*keyword;
51*363e4d4bSyasuoka 	int			 value;
52*363e4d4bSyasuoka 	const struct token	*next;
53*363e4d4bSyasuoka };
54*363e4d4bSyasuoka 
55*363e4d4bSyasuoka static struct parse_result res;
56*363e4d4bSyasuoka 
57*363e4d4bSyasuoka static const struct token t_main[];
58*363e4d4bSyasuoka static const struct token t_session[];
59*363e4d4bSyasuoka static const struct token t_clear[];
60*363e4d4bSyasuoka static const struct token t_filter[];
61*363e4d4bSyasuoka static const struct token t_ppp_id[];
62*363e4d4bSyasuoka static const struct token t_address[];
63*363e4d4bSyasuoka static const struct token t_interface[];
64*363e4d4bSyasuoka static const struct token t_protocol[];
65*363e4d4bSyasuoka static const struct token t_realm[];
66*363e4d4bSyasuoka static const struct token t_username[];
67*363e4d4bSyasuoka 
68*363e4d4bSyasuoka static const struct token t_main[] = {
69*363e4d4bSyasuoka 	{ KEYWORD,	"session",	NONE,		t_session },
70*363e4d4bSyasuoka 	{ KEYWORD,	"clear",	NONE,		t_clear },
71*363e4d4bSyasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
72*363e4d4bSyasuoka };
73*363e4d4bSyasuoka 
74*363e4d4bSyasuoka static const struct token t_session[] = {
75*363e4d4bSyasuoka 	{ KEYWORD,	"brief",	SESSION_BRIEF,	NULL },
76*363e4d4bSyasuoka 	{ KEYWORD,	"packets",	SESSION_PKTS,	NULL },
77*363e4d4bSyasuoka 	{ KEYWORD,	"all",		SESSION_ALL,	t_filter },
78*363e4d4bSyasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
79*363e4d4bSyasuoka };
80*363e4d4bSyasuoka 
81*363e4d4bSyasuoka static const struct token t_clear[] = {
82*363e4d4bSyasuoka 	{ KEYWORD,	"all",		CLEAR_SESSION,	NULL },
83*363e4d4bSyasuoka 	{ KEYWORD,	"ppp-id",	CLEAR_SESSION,	t_ppp_id },
84*363e4d4bSyasuoka 	{ KEYWORD,	"address",	CLEAR_SESSION,	t_address },
85*363e4d4bSyasuoka 	{ KEYWORD,	"interface",	CLEAR_SESSION,	t_interface },
86*363e4d4bSyasuoka 	{ KEYWORD,	"protocol",	CLEAR_SESSION,	t_protocol },
87*363e4d4bSyasuoka 	{ KEYWORD,	"realm",	CLEAR_SESSION,	t_realm },
88*363e4d4bSyasuoka 	{ KEYWORD,	"username",	CLEAR_SESSION,	t_username },
89*363e4d4bSyasuoka 	{ ENDTOKEN,	"",		CLEAR_SESSION,	NULL }
90*363e4d4bSyasuoka };
91*363e4d4bSyasuoka 
92*363e4d4bSyasuoka static const struct token t_filter[] = {
93*363e4d4bSyasuoka 	{ NOTOKEN,	"",		NONE,		NULL },
94*363e4d4bSyasuoka 	{ KEYWORD,	"ppp-id",	NONE,		t_ppp_id },
95*363e4d4bSyasuoka 	{ KEYWORD,	"address",	NONE,		t_address },
96*363e4d4bSyasuoka 	{ KEYWORD,	"interface",	NONE,		t_interface },
97*363e4d4bSyasuoka 	{ KEYWORD,	"protocol",	NONE,		t_protocol },
98*363e4d4bSyasuoka 	{ KEYWORD,	"realm",	NONE,		t_realm },
99*363e4d4bSyasuoka 	{ KEYWORD,	"username",	NONE,		t_username },
100*363e4d4bSyasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
101*363e4d4bSyasuoka };
102*363e4d4bSyasuoka 
103*363e4d4bSyasuoka static const struct token t_ppp_id[] = {
104*363e4d4bSyasuoka 	{ PPP_ID,	"",		NONE,			t_filter },
105*363e4d4bSyasuoka 	{ ENDTOKEN,	"",		NONE,			NULL }
106*363e4d4bSyasuoka };
107*363e4d4bSyasuoka static const struct token t_address[] = {
108*363e4d4bSyasuoka 	{ ADDRESS,	"",		NONE,			t_filter },
109*363e4d4bSyasuoka 	{ ENDTOKEN,	"",		NONE,			NULL }
110*363e4d4bSyasuoka };
111*363e4d4bSyasuoka static const struct token t_interface[] = {
112*363e4d4bSyasuoka 	{ INTERFACE,	"",		NONE,			t_filter },
113*363e4d4bSyasuoka 	{ ENDTOKEN,	"",		NONE,			NULL }
114*363e4d4bSyasuoka };
115*363e4d4bSyasuoka static const struct token t_protocol[] = {
116*363e4d4bSyasuoka 	{ PROTOCOL,	"",		NONE,			t_filter },
117*363e4d4bSyasuoka 	{ ENDTOKEN,	"",		NONE,			NULL }
118*363e4d4bSyasuoka };
119*363e4d4bSyasuoka static const struct token t_realm[] = {
120*363e4d4bSyasuoka 	{ REALM,	"",		NONE,			t_filter },
121*363e4d4bSyasuoka 	{ ENDTOKEN,	"",		NONE,			NULL }
122*363e4d4bSyasuoka };
123*363e4d4bSyasuoka static const struct token t_username[] = {
124*363e4d4bSyasuoka 	{ USERNAME,	"",		NONE,			t_filter },
125*363e4d4bSyasuoka 	{ ENDTOKEN,	"",		NONE,			NULL }
126*363e4d4bSyasuoka };
127*363e4d4bSyasuoka 
128*363e4d4bSyasuoka static const struct token	*match_token(char *, const struct token []);
129*363e4d4bSyasuoka static void			 show_valid_args(const struct token []);
130*363e4d4bSyasuoka 
131*363e4d4bSyasuoka struct parse_result *
132*363e4d4bSyasuoka parse(int argc, char *argv[])
133*363e4d4bSyasuoka {
134*363e4d4bSyasuoka 	const struct token	*table = t_main;
135*363e4d4bSyasuoka 	const struct token	*match;
136*363e4d4bSyasuoka 
137*363e4d4bSyasuoka 	bzero(&res, sizeof(res));
138*363e4d4bSyasuoka 
139*363e4d4bSyasuoka 	while (argc >= 0) {
140*363e4d4bSyasuoka 		if ((match = match_token(argv[0], table)) == NULL) {
141*363e4d4bSyasuoka 			fprintf(stderr, "valid commands/args:\n");
142*363e4d4bSyasuoka 			show_valid_args(table);
143*363e4d4bSyasuoka 			return (NULL);
144*363e4d4bSyasuoka 		}
145*363e4d4bSyasuoka 
146*363e4d4bSyasuoka 		argc--;
147*363e4d4bSyasuoka 		argv++;
148*363e4d4bSyasuoka 
149*363e4d4bSyasuoka 		if (match->type == NOTOKEN || match->next == NULL)
150*363e4d4bSyasuoka 			break;
151*363e4d4bSyasuoka 
152*363e4d4bSyasuoka 		table = match->next;
153*363e4d4bSyasuoka 	}
154*363e4d4bSyasuoka 
155*363e4d4bSyasuoka 	if (argc > 0) {
156*363e4d4bSyasuoka 		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
157*363e4d4bSyasuoka 		return (NULL);
158*363e4d4bSyasuoka 	}
159*363e4d4bSyasuoka 
160*363e4d4bSyasuoka 	return (&res);
161*363e4d4bSyasuoka }
162*363e4d4bSyasuoka 
163*363e4d4bSyasuoka static const struct token *
164*363e4d4bSyasuoka match_token(char *word, const struct token table[])
165*363e4d4bSyasuoka {
166*363e4d4bSyasuoka 	u_int			 i, match = 0;
167*363e4d4bSyasuoka 	unsigned long int	 ulval;
168*363e4d4bSyasuoka 	const struct token	*t = NULL;
169*363e4d4bSyasuoka 	char			*ep;
170*363e4d4bSyasuoka 
171*363e4d4bSyasuoka 	for (i = 0; table[i].type != ENDTOKEN; i++) {
172*363e4d4bSyasuoka 		switch (table[i].type) {
173*363e4d4bSyasuoka 		case NOTOKEN:
174*363e4d4bSyasuoka 			if (word == NULL || strlen(word) == 0) {
175*363e4d4bSyasuoka 				match++;
176*363e4d4bSyasuoka 				t = &table[i];
177*363e4d4bSyasuoka 			}
178*363e4d4bSyasuoka 			break;
179*363e4d4bSyasuoka 		case KEYWORD:
180*363e4d4bSyasuoka 
181*363e4d4bSyasuoka 			if (word != NULL && strncmp(word, table[i].keyword,
182*363e4d4bSyasuoka 			    strlen(word)) == 0) {
183*363e4d4bSyasuoka 				match++;
184*363e4d4bSyasuoka 				t = &table[i];
185*363e4d4bSyasuoka 				if (t->value)
186*363e4d4bSyasuoka 					res.action = t->value;
187*363e4d4bSyasuoka 			}
188*363e4d4bSyasuoka 			break;
189*363e4d4bSyasuoka 		case PPP_ID:
190*363e4d4bSyasuoka 			if (word == NULL)
191*363e4d4bSyasuoka 				break;
192*363e4d4bSyasuoka 			errno = 0;
193*363e4d4bSyasuoka 			ulval = strtoul(word, &ep, 10);
194*363e4d4bSyasuoka 			if (isdigit((unsigned char)*word) && *ep == '\0' &&
195*363e4d4bSyasuoka 			    !(errno == ERANGE && ulval == ULONG_MAX)) {
196*363e4d4bSyasuoka 				res.ppp_id = ulval;
197*363e4d4bSyasuoka 				res.has_ppp_id = 1;
198*363e4d4bSyasuoka 				match++;
199*363e4d4bSyasuoka 				t = &table[i];
200*363e4d4bSyasuoka 			}
201*363e4d4bSyasuoka 			break;
202*363e4d4bSyasuoka 		case ADDRESS:
203*363e4d4bSyasuoka 		    {
204*363e4d4bSyasuoka 			struct sockaddr_in sin4 = {
205*363e4d4bSyasuoka 				.sin_family = AF_INET,
206*363e4d4bSyasuoka 				.sin_len = sizeof(struct sockaddr_in)
207*363e4d4bSyasuoka 			};
208*363e4d4bSyasuoka 			struct sockaddr_in6 sin6 = {
209*363e4d4bSyasuoka 				.sin6_family = AF_INET6,
210*363e4d4bSyasuoka 				.sin6_len = sizeof(struct sockaddr_in6)
211*363e4d4bSyasuoka 			};
212*363e4d4bSyasuoka 			if (word == NULL)
213*363e4d4bSyasuoka 				break;
214*363e4d4bSyasuoka 			if (inet_pton(AF_INET, word, &sin4.sin_addr) == 1)
215*363e4d4bSyasuoka 				memcpy(&res.address, &sin4, sin4.sin_len);
216*363e4d4bSyasuoka 			else
217*363e4d4bSyasuoka 			if (inet_pton(AF_INET6, word, &sin6.sin6_addr) == 1)
218*363e4d4bSyasuoka 				memcpy(&res.address, &sin6, sin6.sin6_len);
219*363e4d4bSyasuoka 			else
220*363e4d4bSyasuoka 				break;
221*363e4d4bSyasuoka 			match++;
222*363e4d4bSyasuoka 			t = &table[i];
223*363e4d4bSyasuoka 		    }
224*363e4d4bSyasuoka 			break;
225*363e4d4bSyasuoka 		case INTERFACE:
226*363e4d4bSyasuoka 			if (word == NULL)
227*363e4d4bSyasuoka 				break;
228*363e4d4bSyasuoka 			res.interface = word;
229*363e4d4bSyasuoka 			match++;
230*363e4d4bSyasuoka 			t = &table[i];
231*363e4d4bSyasuoka 			break;
232*363e4d4bSyasuoka 		case PROTOCOL:
233*363e4d4bSyasuoka 			if (word == NULL)
234*363e4d4bSyasuoka 				break;
235*363e4d4bSyasuoka 			if ((res.protocol = parse_protocol(word)) ==
236*363e4d4bSyasuoka 			    PROTO_UNSPEC)
237*363e4d4bSyasuoka 				break;
238*363e4d4bSyasuoka 			match++;
239*363e4d4bSyasuoka 			t = &table[i];
240*363e4d4bSyasuoka 			break;
241*363e4d4bSyasuoka 		case REALM:
242*363e4d4bSyasuoka 			if (word == NULL)
243*363e4d4bSyasuoka 				break;
244*363e4d4bSyasuoka 			res.realm = word;
245*363e4d4bSyasuoka 			match++;
246*363e4d4bSyasuoka 			t = &table[i];
247*363e4d4bSyasuoka 			break;
248*363e4d4bSyasuoka 		case USERNAME:
249*363e4d4bSyasuoka 			if (word == NULL)
250*363e4d4bSyasuoka 				break;
251*363e4d4bSyasuoka 			res.username = word;
252*363e4d4bSyasuoka 			match++;
253*363e4d4bSyasuoka 			t = &table[i];
254*363e4d4bSyasuoka 			break;
255*363e4d4bSyasuoka 		case ENDTOKEN:
256*363e4d4bSyasuoka 			break;
257*363e4d4bSyasuoka 		}
258*363e4d4bSyasuoka 	}
259*363e4d4bSyasuoka 
260*363e4d4bSyasuoka 	if (match != 1) {
261*363e4d4bSyasuoka 		if (word == NULL)
262*363e4d4bSyasuoka 			fprintf(stderr, "missing argument:\n");
263*363e4d4bSyasuoka 		else if (match > 1)
264*363e4d4bSyasuoka 			fprintf(stderr, "ambiguous argument: %s\n", word);
265*363e4d4bSyasuoka 		else if (match < 1)
266*363e4d4bSyasuoka 			fprintf(stderr, "unknown argument: %s\n", word);
267*363e4d4bSyasuoka 		return (NULL);
268*363e4d4bSyasuoka 	}
269*363e4d4bSyasuoka 
270*363e4d4bSyasuoka 	return (t);
271*363e4d4bSyasuoka }
272*363e4d4bSyasuoka 
273*363e4d4bSyasuoka static void
274*363e4d4bSyasuoka show_valid_args(const struct token table[])
275*363e4d4bSyasuoka {
276*363e4d4bSyasuoka 	int	i;
277*363e4d4bSyasuoka 
278*363e4d4bSyasuoka 	for (i = 0; table[i].type != ENDTOKEN; i++) {
279*363e4d4bSyasuoka 		switch (table[i].type) {
280*363e4d4bSyasuoka 		case NOTOKEN:
281*363e4d4bSyasuoka 			fprintf(stderr, "  <cr>\n");
282*363e4d4bSyasuoka 			break;
283*363e4d4bSyasuoka 		case KEYWORD:
284*363e4d4bSyasuoka 			fprintf(stderr, "  %s\n", table[i].keyword);
285*363e4d4bSyasuoka 			break;
286*363e4d4bSyasuoka 		case PPP_ID:
287*363e4d4bSyasuoka 			fprintf(stderr, "  <ppp-id>\n");
288*363e4d4bSyasuoka 			break;
289*363e4d4bSyasuoka 		case ADDRESS:
290*363e4d4bSyasuoka 			fprintf(stderr, "  <address>\n");
291*363e4d4bSyasuoka 			break;
292*363e4d4bSyasuoka 		case INTERFACE:
293*363e4d4bSyasuoka 			fprintf(stderr, "  <interface>\n");
294*363e4d4bSyasuoka 			break;
295*363e4d4bSyasuoka 		case PROTOCOL:
296*363e4d4bSyasuoka 			fprintf(stderr, "  [ pppoe | l2tp | pptp | sstp ]\n");
297*363e4d4bSyasuoka 			break;
298*363e4d4bSyasuoka 		case REALM:
299*363e4d4bSyasuoka 			fprintf(stderr, "  <realm>\n");
300*363e4d4bSyasuoka 			break;
301*363e4d4bSyasuoka 		case USERNAME:
302*363e4d4bSyasuoka 			fprintf(stderr, "  <username>\n");
303*363e4d4bSyasuoka 			break;
304*363e4d4bSyasuoka 		case ENDTOKEN:
305*363e4d4bSyasuoka 			break;
306*363e4d4bSyasuoka 		}
307*363e4d4bSyasuoka 	}
308*363e4d4bSyasuoka }
309*363e4d4bSyasuoka 
310*363e4d4bSyasuoka enum protocol
311*363e4d4bSyasuoka parse_protocol(const char *str)
312*363e4d4bSyasuoka {
313*363e4d4bSyasuoka 	return
314*363e4d4bSyasuoka 	    (strcasecmp(str, "PPTP" ) == 0)? PPTP  :
315*363e4d4bSyasuoka 	    (strcasecmp(str, "L2TP" ) == 0)? L2TP  :
316*363e4d4bSyasuoka 	    (strcasecmp(str, "PPPoE") == 0)? PPPOE :
317*363e4d4bSyasuoka 	    (strcasecmp(str, "SSTP" ) == 0)? SSTP  : PROTO_UNSPEC;
318*363e4d4bSyasuoka }
319*363e4d4bSyasuoka 
320