xref: /openbsd-src/usr.sbin/npppctl/parser.c (revision dbad4650ad35235393a341c80d161513d6691849)
1 /*	$OpenBSD: parser.c,v 1.3 2015/01/19 01:48:57 deraadt 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/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 
26 #include <ctype.h>
27 #include <errno.h>
28 #include <limits.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include "parser.h"
34 
35 enum token_type {
36 	NOTOKEN,
37 	ENDTOKEN,
38 	KEYWORD,
39 	PPP_ID,
40 	ADDRESS,
41 	INTERFACE,
42 	PROTOCOL,
43 	REALM,
44 	USERNAME
45 };
46 
47 struct token {
48 	enum token_type		 type;
49 	const char		*keyword;
50 	int			 value;
51 	const struct token	*next;
52 };
53 
54 static struct parse_result res;
55 
56 static const struct token t_main[];
57 static const struct token t_session[];
58 static const struct token t_clear[];
59 static const struct token t_monitor[];
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 	{ KEYWORD,	"monitor",	NONE,		t_monitor },
72 	{ ENDTOKEN,	"",		NONE,		NULL }
73 };
74 
75 static const struct token t_session[] = {
76 	{ KEYWORD,	"brief",	SESSION_BRIEF,	NULL },
77 	{ KEYWORD,	"packets",	SESSION_PKTS,	NULL },
78 	{ KEYWORD,	"all",		SESSION_ALL,	t_filter },
79 	{ ENDTOKEN,	"",		NONE,		NULL }
80 };
81 
82 static const struct token t_clear[] = {
83 	{ KEYWORD,	"all",		CLEAR_SESSION,	NULL },
84 	{ KEYWORD,	"ppp-id",	CLEAR_SESSION,	t_ppp_id },
85 	{ KEYWORD,	"address",	CLEAR_SESSION,	t_address },
86 	{ KEYWORD,	"interface",	CLEAR_SESSION,	t_interface },
87 	{ KEYWORD,	"protocol",	CLEAR_SESSION,	t_protocol },
88 	{ KEYWORD,	"realm",	CLEAR_SESSION,	t_realm },
89 	{ KEYWORD,	"username",	CLEAR_SESSION,	t_username },
90 	{ ENDTOKEN,	"",		CLEAR_SESSION,	NULL }
91 };
92 
93 static const struct token t_monitor[] = {
94 	{ KEYWORD,	"all",		MONITOR_SESSION,	NULL },
95 	{ KEYWORD,	"ppp-id",	MONITOR_SESSION,	t_ppp_id },
96 	{ KEYWORD,	"address",	MONITOR_SESSION,	t_address },
97 	{ KEYWORD,	"interface",	MONITOR_SESSION,	t_interface },
98 	{ KEYWORD,	"protocol",	MONITOR_SESSION,	t_protocol },
99 	{ KEYWORD,	"realm",	MONITOR_SESSION,	t_realm },
100 	{ KEYWORD,	"username",	MONITOR_SESSION,	t_username },
101 	{ ENDTOKEN,	"",		MONITOR_SESSION,	NULL }
102 };
103 
104 static const struct token t_filter[] = {
105 	{ NOTOKEN,	"",		NONE,		NULL },
106 	{ KEYWORD,	"ppp-id",	NONE,		t_ppp_id },
107 	{ KEYWORD,	"address",	NONE,		t_address },
108 	{ KEYWORD,	"interface",	NONE,		t_interface },
109 	{ KEYWORD,	"protocol",	NONE,		t_protocol },
110 	{ KEYWORD,	"realm",	NONE,		t_realm },
111 	{ KEYWORD,	"username",	NONE,		t_username },
112 	{ ENDTOKEN,	"",		NONE,		NULL }
113 };
114 
115 static const struct token t_ppp_id[] = {
116 	{ PPP_ID,	"",		NONE,			t_filter },
117 	{ ENDTOKEN,	"",		NONE,			NULL }
118 };
119 static const struct token t_address[] = {
120 	{ ADDRESS,	"",		NONE,			t_filter },
121 	{ ENDTOKEN,	"",		NONE,			NULL }
122 };
123 static const struct token t_interface[] = {
124 	{ INTERFACE,	"",		NONE,			t_filter },
125 	{ ENDTOKEN,	"",		NONE,			NULL }
126 };
127 static const struct token t_protocol[] = {
128 	{ PROTOCOL,	"",		NONE,			t_filter },
129 	{ ENDTOKEN,	"",		NONE,			NULL }
130 };
131 static const struct token t_realm[] = {
132 	{ REALM,	"",		NONE,			t_filter },
133 	{ ENDTOKEN,	"",		NONE,			NULL }
134 };
135 static const struct token t_username[] = {
136 	{ USERNAME,	"",		NONE,			t_filter },
137 	{ ENDTOKEN,	"",		NONE,			NULL }
138 };
139 
140 static const struct token	*match_token(char *, const struct token []);
141 static void			 show_valid_args(const struct token []);
142 
143 struct parse_result *
parse(int argc,char * argv[])144 parse(int argc, char *argv[])
145 {
146 	const struct token	*table = t_main;
147 	const struct token	*match;
148 
149 	bzero(&res, sizeof(res));
150 
151 	while (argc >= 0) {
152 		if ((match = match_token(argv[0], table)) == NULL) {
153 			fprintf(stderr, "valid commands/args:\n");
154 			show_valid_args(table);
155 			return (NULL);
156 		}
157 
158 		argc--;
159 		argv++;
160 
161 		if (match->type == NOTOKEN || match->next == NULL)
162 			break;
163 
164 		table = match->next;
165 	}
166 
167 	if (argc > 0) {
168 		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
169 		return (NULL);
170 	}
171 
172 	return (&res);
173 }
174 
175 static const struct token *
match_token(char * word,const struct token table[])176 match_token(char *word, const struct token table[])
177 {
178 	u_int			 i, match = 0;
179 	unsigned long int	 ulval;
180 	const struct token	*t = NULL;
181 	char			*ep;
182 
183 	for (i = 0; table[i].type != ENDTOKEN; i++) {
184 		switch (table[i].type) {
185 		case NOTOKEN:
186 			if (word == NULL || strlen(word) == 0) {
187 				match++;
188 				t = &table[i];
189 			}
190 			break;
191 		case KEYWORD:
192 
193 			if (word != NULL && strncmp(word, table[i].keyword,
194 			    strlen(word)) == 0) {
195 				match++;
196 				t = &table[i];
197 				if (t->value)
198 					res.action = t->value;
199 			}
200 			break;
201 		case PPP_ID:
202 			if (word == NULL)
203 				break;
204 			errno = 0;
205 			ulval = strtoul(word, &ep, 10);
206 			if (isdigit((unsigned char)*word) && *ep == '\0' &&
207 			    !(errno == ERANGE && ulval == ULONG_MAX)) {
208 				res.ppp_id = ulval;
209 				res.has_ppp_id = 1;
210 				match++;
211 				t = &table[i];
212 			}
213 			break;
214 		case ADDRESS:
215 		    {
216 			struct sockaddr_in sin4 = {
217 				.sin_family = AF_INET,
218 				.sin_len = sizeof(struct sockaddr_in)
219 			};
220 			struct sockaddr_in6 sin6 = {
221 				.sin6_family = AF_INET6,
222 				.sin6_len = sizeof(struct sockaddr_in6)
223 			};
224 			if (word == NULL)
225 				break;
226 			if (inet_pton(AF_INET, word, &sin4.sin_addr) == 1)
227 				memcpy(&res.address, &sin4, sin4.sin_len);
228 			else
229 			if (inet_pton(AF_INET6, word, &sin6.sin6_addr) == 1)
230 				memcpy(&res.address, &sin6, sin6.sin6_len);
231 			else
232 				break;
233 			match++;
234 			t = &table[i];
235 		    }
236 			break;
237 		case INTERFACE:
238 			if (word == NULL)
239 				break;
240 			res.interface = word;
241 			match++;
242 			t = &table[i];
243 			break;
244 		case PROTOCOL:
245 			if (word == NULL)
246 				break;
247 			if ((res.protocol = parse_protocol(word)) ==
248 			    PROTO_UNSPEC)
249 				break;
250 			match++;
251 			t = &table[i];
252 			break;
253 		case REALM:
254 			if (word == NULL)
255 				break;
256 			res.realm = word;
257 			match++;
258 			t = &table[i];
259 			break;
260 		case USERNAME:
261 			if (word == NULL)
262 				break;
263 			res.username = word;
264 			match++;
265 			t = &table[i];
266 			break;
267 		case ENDTOKEN:
268 			break;
269 		}
270 	}
271 
272 	if (match != 1) {
273 		if (word == NULL)
274 			fprintf(stderr, "missing argument:\n");
275 		else if (match > 1)
276 			fprintf(stderr, "ambiguous argument: %s\n", word);
277 		else if (match < 1)
278 			fprintf(stderr, "unknown argument: %s\n", word);
279 		return (NULL);
280 	}
281 
282 	return (t);
283 }
284 
285 static void
show_valid_args(const struct token table[])286 show_valid_args(const struct token table[])
287 {
288 	int	i;
289 
290 	for (i = 0; table[i].type != ENDTOKEN; i++) {
291 		switch (table[i].type) {
292 		case NOTOKEN:
293 			fprintf(stderr, "  <cr>\n");
294 			break;
295 		case KEYWORD:
296 			fprintf(stderr, "  %s\n", table[i].keyword);
297 			break;
298 		case PPP_ID:
299 			fprintf(stderr, "  <ppp-id>\n");
300 			break;
301 		case ADDRESS:
302 			fprintf(stderr, "  <address>\n");
303 			break;
304 		case INTERFACE:
305 			fprintf(stderr, "  <interface>\n");
306 			break;
307 		case PROTOCOL:
308 			fprintf(stderr, "  [ pppoe | l2tp | pptp | sstp ]\n");
309 			break;
310 		case REALM:
311 			fprintf(stderr, "  <realm>\n");
312 			break;
313 		case USERNAME:
314 			fprintf(stderr, "  <username>\n");
315 			break;
316 		case ENDTOKEN:
317 			break;
318 		}
319 	}
320 }
321 
322 enum protocol
parse_protocol(const char * str)323 parse_protocol(const char *str)
324 {
325 	return
326 	    (strcasecmp(str, "PPTP" ) == 0)? PPTP  :
327 	    (strcasecmp(str, "L2TP" ) == 0)? L2TP  :
328 	    (strcasecmp(str, "PPPoE") == 0)? PPPOE :
329 	    (strcasecmp(str, "SSTP" ) == 0)? SSTP  : PROTO_UNSPEC;
330 }
331 
332