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