GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/npppctl/parser.c Lines: 0 89 0.0 %
Date: 2017-11-07 Branches: 0 80 0.0 %

Line Branch Exec Source
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 *
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 *
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
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
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