xref: /openbsd-src/usr.sbin/radiusctl/parser.c (revision eff8f878b4e2b3d555135dc11d9e6d72aadadea0)
1*eff8f878Syasuoka /*	$OpenBSD: parser.c,v 1.6 2024/09/15 05:26:05 yasuoka Exp $	*/
2a7ca44b8Syasuoka 
3a7ca44b8Syasuoka /*
4a7ca44b8Syasuoka  * Copyright (c) 2010 Reyk Floeter <reyk@vantronix.net>
5a7ca44b8Syasuoka  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
6a7ca44b8Syasuoka  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7a7ca44b8Syasuoka  *
8a7ca44b8Syasuoka  * Permission to use, copy, modify, and distribute this software for any
9a7ca44b8Syasuoka  * purpose with or without fee is hereby granted, provided that the above
10a7ca44b8Syasuoka  * copyright notice and this permission notice appear in all copies.
11a7ca44b8Syasuoka  *
12a7ca44b8Syasuoka  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13a7ca44b8Syasuoka  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14a7ca44b8Syasuoka  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15a7ca44b8Syasuoka  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16a7ca44b8Syasuoka  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17a7ca44b8Syasuoka  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18a7ca44b8Syasuoka  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19a7ca44b8Syasuoka  */
20a7ca44b8Syasuoka 
215d013a5eSdlg #include <sys/time.h>
225d013a5eSdlg 
23a7ca44b8Syasuoka #include <stdint.h>
24a7ca44b8Syasuoka #include <stdio.h>
25a7ca44b8Syasuoka #include <stdlib.h>
26a7ca44b8Syasuoka #include <string.h>
27842565f2Syasuoka #include <strings.h>
28842565f2Syasuoka #include <limits.h>
29a7ca44b8Syasuoka 
30a7ca44b8Syasuoka #include "parser.h"
31a7ca44b8Syasuoka 
32a7ca44b8Syasuoka enum token_type {
33a7ca44b8Syasuoka 	NOTOKEN,
34a7ca44b8Syasuoka 	KEYWORD,
35a7ca44b8Syasuoka 	HOSTNAME,
36a7ca44b8Syasuoka 	SECRET,
37a7ca44b8Syasuoka 	USERNAME,
38a7ca44b8Syasuoka 	PASSWORD,
39a7ca44b8Syasuoka 	PORT,
40a7ca44b8Syasuoka 	METHOD,
41a7ca44b8Syasuoka 	NAS_PORT,
425d013a5eSdlg 	TRIES,
435d013a5eSdlg 	INTERVAL,
445d013a5eSdlg 	MAXWAIT,
45842565f2Syasuoka 	FLAGS,
46842565f2Syasuoka 	SESSION_SEQ,
47a852e27aSyasuoka 	MSGAUTH,
48a7ca44b8Syasuoka 	ENDTOKEN
49a7ca44b8Syasuoka };
50a7ca44b8Syasuoka 
51a7ca44b8Syasuoka struct token {
52a7ca44b8Syasuoka 	enum token_type		 type;
53a7ca44b8Syasuoka 	const char		*keyword;
54a7ca44b8Syasuoka 	int			 value;
55a7ca44b8Syasuoka 	const struct token	*next;
56a7ca44b8Syasuoka };
57a7ca44b8Syasuoka 
585d013a5eSdlg static struct parse_result res = {
595d013a5eSdlg 	.tries		= TEST_TRIES_DEFAULT,
605d013a5eSdlg 	.interval	= { TEST_INTERVAL_DEFAULT, 0 },
615d013a5eSdlg 	.maxwait	= { TEST_MAXWAIT_DEFAULT, 0 },
62a852e27aSyasuoka 	.msgauth	= 1
635d013a5eSdlg };
64a7ca44b8Syasuoka 
65a7ca44b8Syasuoka static const struct token t_test[];
66a7ca44b8Syasuoka static const struct token t_secret[];
67a7ca44b8Syasuoka static const struct token t_username[];
68a7ca44b8Syasuoka static const struct token t_test_opts[];
69a7ca44b8Syasuoka static const struct token t_password[];
70a7ca44b8Syasuoka static const struct token t_port[];
71a7ca44b8Syasuoka static const struct token t_method[];
72a7ca44b8Syasuoka static const struct token t_nas_port[];
735d013a5eSdlg static const struct token t_tries[];
745d013a5eSdlg static const struct token t_interval[];
755d013a5eSdlg static const struct token t_maxwait[];
76a852e27aSyasuoka static const struct token t_yesno[];
77842565f2Syasuoka static const struct token t_ipcp[];
78842565f2Syasuoka static const struct token t_ipcp_flags[];
79842565f2Syasuoka static const struct token t_ipcp_session_seq[];
80a7ca44b8Syasuoka 
81a7ca44b8Syasuoka static const struct token t_main[] = {
82a7ca44b8Syasuoka 	{ KEYWORD,	"test",		TEST,		t_test },
83842565f2Syasuoka 	{ KEYWORD,	"ipcp",		NONE,		t_ipcp },
84a7ca44b8Syasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
85a7ca44b8Syasuoka };
86a7ca44b8Syasuoka 
87a7ca44b8Syasuoka static const struct token t_test[] = {
88a7ca44b8Syasuoka 	{ HOSTNAME,	"",		NONE,		t_secret },
89a7ca44b8Syasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
90a7ca44b8Syasuoka };
91a7ca44b8Syasuoka 
92a7ca44b8Syasuoka static const struct token t_secret[] = {
93a7ca44b8Syasuoka 	{ SECRET,	"",		NONE,		t_username },
94a7ca44b8Syasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
95a7ca44b8Syasuoka };
96a7ca44b8Syasuoka 
97a7ca44b8Syasuoka static const struct token t_username[] = {
98a7ca44b8Syasuoka 	{ USERNAME,	"",		NONE,		t_test_opts },
99a7ca44b8Syasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
100a7ca44b8Syasuoka };
101a7ca44b8Syasuoka 
102a7ca44b8Syasuoka static const struct token t_test_opts[] = {
103a7ca44b8Syasuoka 	{ NOTOKEN,	"",		NONE,		NULL },
104a7ca44b8Syasuoka 	{ KEYWORD,	"password",	NONE,		t_password },
105a7ca44b8Syasuoka 	{ KEYWORD,	"port",		NONE,		t_port },
106a7ca44b8Syasuoka 	{ KEYWORD,	"method",	NONE,		t_method },
107a7ca44b8Syasuoka 	{ KEYWORD,	"nas-port",	NONE,		t_nas_port },
1085d013a5eSdlg 	{ KEYWORD,	"interval",	NONE,		t_interval },
1095d013a5eSdlg 	{ KEYWORD,	"tries",	NONE,		t_tries },
1105d013a5eSdlg 	{ KEYWORD,	"maxwait",	NONE,		t_maxwait },
111a852e27aSyasuoka 	{ KEYWORD,	"msgauth",	NONE,		t_yesno },
112a7ca44b8Syasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
113a7ca44b8Syasuoka };
114a7ca44b8Syasuoka 
115a7ca44b8Syasuoka static const struct token t_password[] = {
116a7ca44b8Syasuoka 	{ PASSWORD,	"",		NONE,		t_test_opts },
117a7ca44b8Syasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
118a7ca44b8Syasuoka };
119a7ca44b8Syasuoka 
120a7ca44b8Syasuoka static const struct token t_port[] = {
121a7ca44b8Syasuoka 	{ PORT,		"",		NONE,		t_test_opts },
122a7ca44b8Syasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
123a7ca44b8Syasuoka };
124a7ca44b8Syasuoka 
125a7ca44b8Syasuoka static const struct token t_method[] = {
126a7ca44b8Syasuoka 	{ METHOD,	"",		NONE,		t_test_opts },
127a7ca44b8Syasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
128a7ca44b8Syasuoka };
129a7ca44b8Syasuoka 
130a7ca44b8Syasuoka static const struct token t_nas_port[] = {
131a7ca44b8Syasuoka 	{ NAS_PORT,	"",		NONE,		t_test_opts },
132a7ca44b8Syasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
133a7ca44b8Syasuoka };
134a7ca44b8Syasuoka 
1355d013a5eSdlg static const struct token t_tries[] = {
1365d013a5eSdlg 	{ TRIES,	"",		NONE,		t_test_opts },
1375d013a5eSdlg 	{ ENDTOKEN,	"",		NONE,		NULL }
1385d013a5eSdlg };
1395d013a5eSdlg 
1405d013a5eSdlg static const struct token t_interval[] = {
1415d013a5eSdlg 	{ INTERVAL,	"",		NONE,		t_test_opts },
1425d013a5eSdlg 	{ ENDTOKEN,	"",		NONE,		NULL }
1435d013a5eSdlg };
1445d013a5eSdlg 
1455d013a5eSdlg static const struct token t_maxwait[] = {
1465d013a5eSdlg 	{ MAXWAIT,	"",		NONE,		t_test_opts },
1475d013a5eSdlg 	{ ENDTOKEN,	"",		NONE,		NULL }
1485d013a5eSdlg };
1495d013a5eSdlg 
150a852e27aSyasuoka static const struct token t_yesno[] = {
151a852e27aSyasuoka 	{ MSGAUTH,	"yes",		1,		t_test_opts },
152a852e27aSyasuoka 	{ MSGAUTH,	"no",		0,		t_test_opts },
153a852e27aSyasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
154a852e27aSyasuoka };
155a852e27aSyasuoka 
156842565f2Syasuoka static const struct token t_ipcp[] = {
157842565f2Syasuoka 	{ KEYWORD,	"show",		IPCP_SHOW,	NULL },
158842565f2Syasuoka 	{ KEYWORD,	"dump",		IPCP_DUMP,	t_ipcp_flags },
159842565f2Syasuoka 	{ KEYWORD,	"monitor",	IPCP_MONITOR,	t_ipcp_flags },
160842565f2Syasuoka 	{ KEYWORD,	"disconnect",	IPCP_DISCONNECT,t_ipcp_session_seq },
161*eff8f878Syasuoka 	{ KEYWORD,	"delete",	IPCP_DELETE,	t_ipcp_session_seq },
162842565f2Syasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
163842565f2Syasuoka };
164842565f2Syasuoka 
165842565f2Syasuoka static const struct token t_ipcp_flags[] = {
166842565f2Syasuoka 	{ NOTOKEN,	"",		NONE,		NULL },
167842565f2Syasuoka 	{ FLAGS,	"-json",	FLAGS_JSON,	NULL },
168842565f2Syasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
169842565f2Syasuoka };
170842565f2Syasuoka 
171842565f2Syasuoka static const struct token t_ipcp_session_seq[] = {
172842565f2Syasuoka 	{ SESSION_SEQ,	"",		NONE,		NULL },
173842565f2Syasuoka 	{ ENDTOKEN,	"",		NONE,		NULL }
174842565f2Syasuoka };
175a7ca44b8Syasuoka 
176a7ca44b8Syasuoka static const struct token	*match_token(char *, const struct token []);
177a7ca44b8Syasuoka static void			 show_valid_args(const struct token []);
178a7ca44b8Syasuoka 
179a7ca44b8Syasuoka struct parse_result *
180a7ca44b8Syasuoka parse(int argc, char *argv[])
181a7ca44b8Syasuoka {
182a7ca44b8Syasuoka 	const struct token	*table = t_main;
183a7ca44b8Syasuoka 	const struct token	*match;
184a7ca44b8Syasuoka 
185a7ca44b8Syasuoka 	while (argc >= 0) {
186a7ca44b8Syasuoka 		if ((match = match_token(argv[0], table)) == NULL) {
187a7ca44b8Syasuoka 			fprintf(stderr, "valid commands/args:\n");
188a7ca44b8Syasuoka 			show_valid_args(table);
189a7ca44b8Syasuoka 			return (NULL);
190a7ca44b8Syasuoka 		}
191a7ca44b8Syasuoka 
192a7ca44b8Syasuoka 		argc--;
193a7ca44b8Syasuoka 		argv++;
194a7ca44b8Syasuoka 
195a7ca44b8Syasuoka 		if (match->type == NOTOKEN || match->next == NULL)
196a7ca44b8Syasuoka 			break;
197a7ca44b8Syasuoka 
198a7ca44b8Syasuoka 		table = match->next;
199a7ca44b8Syasuoka 	}
200a7ca44b8Syasuoka 
201a7ca44b8Syasuoka 	if (argc > 0) {
202a7ca44b8Syasuoka 		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
203a7ca44b8Syasuoka 		return (NULL);
204a7ca44b8Syasuoka 	}
205a7ca44b8Syasuoka 
2065d013a5eSdlg 	if (res.tries * res.interval.tv_sec > res.maxwait.tv_sec) {
2075d013a5eSdlg 		fprintf(stderr, "tries %u by interval %lld > maxwait %lld",
2085d013a5eSdlg 		    res.tries, res.interval.tv_sec, res.maxwait.tv_sec);
2095d013a5eSdlg 		return (NULL);
2105d013a5eSdlg 	}
2115d013a5eSdlg 
212a7ca44b8Syasuoka 	return (&res);
213a7ca44b8Syasuoka }
214a7ca44b8Syasuoka 
215a7ca44b8Syasuoka static const struct token *
216a7ca44b8Syasuoka match_token(char *word, const struct token table[])
217a7ca44b8Syasuoka {
218a7ca44b8Syasuoka 	u_int			 i, match = 0;
219a7ca44b8Syasuoka 	const struct token	*t = NULL;
220a7ca44b8Syasuoka 	long long		 num;
221a7ca44b8Syasuoka 	const char		*errstr;
222842565f2Syasuoka 	size_t			 wordlen = 0;
223842565f2Syasuoka 
224842565f2Syasuoka 	if (word != NULL)
225842565f2Syasuoka 		wordlen = strlen(word);
226a7ca44b8Syasuoka 
227a7ca44b8Syasuoka 	for (i = 0; table[i].type != ENDTOKEN; i++) {
228a7ca44b8Syasuoka 		switch (table[i].type) {
229a7ca44b8Syasuoka 		case NOTOKEN:
230a7ca44b8Syasuoka 			if (word == NULL || strlen(word) == 0) {
231a7ca44b8Syasuoka 				match++;
232a7ca44b8Syasuoka 				t = &table[i];
233a7ca44b8Syasuoka 			}
234a7ca44b8Syasuoka 			break;
235a7ca44b8Syasuoka 		case KEYWORD:
236a7ca44b8Syasuoka 			if (word != NULL && strncmp(word, table[i].keyword,
237842565f2Syasuoka 			    wordlen) == 0) {
238a7ca44b8Syasuoka 				match++;
239a7ca44b8Syasuoka 				t = &table[i];
240a7ca44b8Syasuoka 				if (t->value)
241a7ca44b8Syasuoka 					res.action = t->value;
242a7ca44b8Syasuoka 			}
243a7ca44b8Syasuoka 			break;
244a7ca44b8Syasuoka 		case HOSTNAME:
245a7ca44b8Syasuoka 			if (word == NULL)
246a7ca44b8Syasuoka 				break;
247a7ca44b8Syasuoka 			match++;
248a7ca44b8Syasuoka 			res.hostname = word;
249a7ca44b8Syasuoka 			t = &table[i];
250a7ca44b8Syasuoka 			break;
251a7ca44b8Syasuoka 		case SECRET:
252a7ca44b8Syasuoka 			if (word == NULL)
253a7ca44b8Syasuoka 				break;
254a7ca44b8Syasuoka 			match++;
255a7ca44b8Syasuoka 			res.secret = word;
256a7ca44b8Syasuoka 			t = &table[i];
257a7ca44b8Syasuoka 			break;
258a7ca44b8Syasuoka 		case USERNAME:
259a7ca44b8Syasuoka 			if (word == NULL)
260a7ca44b8Syasuoka 				break;
261a7ca44b8Syasuoka 			match++;
262a7ca44b8Syasuoka 			res.username = word;
263a7ca44b8Syasuoka 			t = &table[i];
264a7ca44b8Syasuoka 			break;
265a7ca44b8Syasuoka 		case PASSWORD:
266a7ca44b8Syasuoka 			if (word == NULL)
267a7ca44b8Syasuoka 				break;
268a7ca44b8Syasuoka 			match++;
269a7ca44b8Syasuoka 			res.password = word;
270a7ca44b8Syasuoka 			t = &table[i];
271a7ca44b8Syasuoka 			break;
272a7ca44b8Syasuoka 		case PORT:
273a7ca44b8Syasuoka 			if (word == NULL)
274a7ca44b8Syasuoka 				break;
275a7ca44b8Syasuoka 			num = strtonum(word, 1, UINT16_MAX, &errstr);
276a7ca44b8Syasuoka 			if (errstr != NULL) {
277a7ca44b8Syasuoka 				fprintf(stderr,
278a7ca44b8Syasuoka 				    "invalid argument: %s is %s for \"port\"\n",
279a7ca44b8Syasuoka 				    word, errstr);
280a7ca44b8Syasuoka 				return (NULL);
281a7ca44b8Syasuoka 			}
282a7ca44b8Syasuoka 			match++;
283a7ca44b8Syasuoka 			res.port = num;
284a7ca44b8Syasuoka 			t = &table[i];
285a7ca44b8Syasuoka 			break;
286a7ca44b8Syasuoka 		case METHOD:
287a7ca44b8Syasuoka 			if (word == NULL)
288a7ca44b8Syasuoka 				break;
289a7ca44b8Syasuoka 			if (strcasecmp(word, "pap") == 0)
290a7ca44b8Syasuoka 				res.auth_method = PAP;
291a7ca44b8Syasuoka 			else if (strcasecmp(word, "chap") == 0)
292a7ca44b8Syasuoka 				res.auth_method = CHAP;
293a7ca44b8Syasuoka 			else if (strcasecmp(word, "mschapv2") == 0)
294a7ca44b8Syasuoka 				res.auth_method = MSCHAPV2;
295a7ca44b8Syasuoka 			else {
296a7ca44b8Syasuoka 				fprintf(stderr,
297a7ca44b8Syasuoka 				    "invalid argument: %s for \"method\"\n",
298a7ca44b8Syasuoka 				    word);
299a7ca44b8Syasuoka 				return (NULL);
300a7ca44b8Syasuoka 			}
301a7ca44b8Syasuoka 			match++;
302a7ca44b8Syasuoka 			t = &table[i];
303a7ca44b8Syasuoka 			break;
304a7ca44b8Syasuoka 		case NAS_PORT:
305a7ca44b8Syasuoka 			if (word == NULL)
306a7ca44b8Syasuoka 				break;
307a7ca44b8Syasuoka 			num = strtonum(word, 0, 65535, &errstr);
308a7ca44b8Syasuoka 			if (errstr != NULL) {
309a7ca44b8Syasuoka 				fprintf(stderr,
310a7ca44b8Syasuoka 				    "invalid argument: %s is %s for "
311a7ca44b8Syasuoka 				    "\"nas-port\"\n", word, errstr);
312a7ca44b8Syasuoka 				return (NULL);
313a7ca44b8Syasuoka 			}
314a7ca44b8Syasuoka 			match++;
315a7ca44b8Syasuoka 			res.nas_port = num;
316a7ca44b8Syasuoka 			t = &table[i];
317a7ca44b8Syasuoka 			break;
3185d013a5eSdlg 
3195d013a5eSdlg 		case TRIES:
3205d013a5eSdlg 			if (word == NULL)
3215d013a5eSdlg 				break;
3225d013a5eSdlg 			num = strtonum(word,
3235d013a5eSdlg 			    TEST_TRIES_MIN, TEST_TRIES_MAX, &errstr);
3245d013a5eSdlg 			if (errstr != NULL) {
3255d013a5eSdlg 				printf("invalid argument: %s is %s"
3265d013a5eSdlg 				    " for \"tries\"\n", word, errstr);
3275d013a5eSdlg 				return (NULL);
3285d013a5eSdlg 			}
3295d013a5eSdlg 			match++;
3305d013a5eSdlg 			res.tries = num;
3315d013a5eSdlg 			t = &table[i];
3325d013a5eSdlg 			break;
3335d013a5eSdlg 		case INTERVAL:
3345d013a5eSdlg 			if (word == NULL)
3355d013a5eSdlg 				break;
3365d013a5eSdlg 			num = strtonum(word,
3375d013a5eSdlg 			    TEST_INTERVAL_MIN, TEST_INTERVAL_MAX, &errstr);
3385d013a5eSdlg 			if (errstr != NULL) {
3395d013a5eSdlg 				printf("invalid argument: %s is %s"
3405d013a5eSdlg 				    " for \"interval\"\n", word, errstr);
3415d013a5eSdlg 				return (NULL);
3425d013a5eSdlg 			}
3435d013a5eSdlg 			match++;
3445d013a5eSdlg 			res.interval.tv_sec = num;
3455d013a5eSdlg 			t = &table[i];
3465d013a5eSdlg 			break;
3475d013a5eSdlg 		case MAXWAIT:
3485d013a5eSdlg 			if (word == NULL)
3495d013a5eSdlg 				break;
3505d013a5eSdlg 			num = strtonum(word,
3515d013a5eSdlg 			    TEST_MAXWAIT_MIN, TEST_MAXWAIT_MAX, &errstr);
3525d013a5eSdlg 			if (errstr != NULL) {
3535d013a5eSdlg 				printf("invalid argument: %s is %s"
3545d013a5eSdlg 				    " for \"maxwait\"\n", word, errstr);
3555d013a5eSdlg 				return (NULL);
3565d013a5eSdlg 			}
3575d013a5eSdlg 			match++;
3585d013a5eSdlg 			res.maxwait.tv_sec = num;
3595d013a5eSdlg 			t = &table[i];
3605d013a5eSdlg 			break;
361842565f2Syasuoka 		case FLAGS:
362842565f2Syasuoka 			if (word != NULL && wordlen >= 2 &&
363842565f2Syasuoka 			    strncmp(word, table[i].keyword, wordlen) == 0) {
364842565f2Syasuoka 				match++;
365842565f2Syasuoka 				t = &table[i];
366842565f2Syasuoka 				if (t->value)
367842565f2Syasuoka 					res.flags |= t->value;
368842565f2Syasuoka 			}
369842565f2Syasuoka 			break;
370842565f2Syasuoka 		case SESSION_SEQ:
371842565f2Syasuoka 			if (word == NULL)
372842565f2Syasuoka 				break;
373842565f2Syasuoka 			match++;
374842565f2Syasuoka 			res.session_seq = strtonum(word, 1, UINT_MAX, &errstr);
3757c8f25c7Syasuoka 			if (errstr != NULL) {
376842565f2Syasuoka 				printf("invalid argument: %s is %s for "
3777c8f25c7Syasuoka 				    "\"session-id\"\n", word, errstr);
3787c8f25c7Syasuoka 				return (NULL);
3797c8f25c7Syasuoka 			}
380842565f2Syasuoka 			t = &table[i];
381a852e27aSyasuoka 		case MSGAUTH:
382a852e27aSyasuoka 			if (word != NULL &&
383a852e27aSyasuoka 			    strcmp(word, table[i].keyword) == 0) {
384a852e27aSyasuoka 				match++;
385a852e27aSyasuoka 				res.msgauth = table[i].value;
386a852e27aSyasuoka 				t = &table[i];
387a852e27aSyasuoka 			}
388a852e27aSyasuoka 			break;
389a7ca44b8Syasuoka 		case ENDTOKEN:
390a7ca44b8Syasuoka 			break;
391a7ca44b8Syasuoka 		}
392a7ca44b8Syasuoka 	}
393a7ca44b8Syasuoka 
394a7ca44b8Syasuoka 	if (match != 1) {
395a7ca44b8Syasuoka 		if (word == NULL)
396a7ca44b8Syasuoka 			fprintf(stderr, "missing argument:\n");
397a7ca44b8Syasuoka 		else if (match > 1)
398a7ca44b8Syasuoka 			fprintf(stderr, "ambiguous argument: %s\n", word);
399a7ca44b8Syasuoka 		else if (match < 1)
400a7ca44b8Syasuoka 			fprintf(stderr, "unknown argument: %s\n", word);
401a7ca44b8Syasuoka 		return (NULL);
402a7ca44b8Syasuoka 	}
403a7ca44b8Syasuoka 
404a7ca44b8Syasuoka 	return (t);
405a7ca44b8Syasuoka }
406a7ca44b8Syasuoka 
407a7ca44b8Syasuoka static void
408a7ca44b8Syasuoka show_valid_args(const struct token table[])
409a7ca44b8Syasuoka {
410a7ca44b8Syasuoka 	int	i;
411a7ca44b8Syasuoka 
412a7ca44b8Syasuoka 	for (i = 0; table[i].type != ENDTOKEN; i++) {
413a7ca44b8Syasuoka 		switch (table[i].type) {
414a7ca44b8Syasuoka 		case NOTOKEN:
415a7ca44b8Syasuoka 			fprintf(stderr, "  <cr>\n");
416a7ca44b8Syasuoka 			break;
417a7ca44b8Syasuoka 		case KEYWORD:
418a7ca44b8Syasuoka 			fprintf(stderr, "  %s\n", table[i].keyword);
419a7ca44b8Syasuoka 			break;
420a7ca44b8Syasuoka 		case HOSTNAME:
421a7ca44b8Syasuoka 			fprintf(stderr, "  <hostname>\n");
422a7ca44b8Syasuoka 			break;
423a7ca44b8Syasuoka 		case SECRET:
424a7ca44b8Syasuoka 			fprintf(stderr, "  <radius secret>\n");
425a7ca44b8Syasuoka 			break;
426a7ca44b8Syasuoka 		case USERNAME:
427a7ca44b8Syasuoka 			fprintf(stderr, "  <username>\n");
428a7ca44b8Syasuoka 			break;
429a7ca44b8Syasuoka 		case PASSWORD:
430a7ca44b8Syasuoka 			fprintf(stderr, "  <password>\n");
431a7ca44b8Syasuoka 			break;
432a7ca44b8Syasuoka 		case PORT:
433a7ca44b8Syasuoka 			fprintf(stderr, "  <port number>\n");
434a7ca44b8Syasuoka 			break;
435a7ca44b8Syasuoka 		case METHOD:
436a7ca44b8Syasuoka 			fprintf(stderr, "  <auth method (pap, chap, "
437a7ca44b8Syasuoka 			    "mschapv2)>\n");
438a7ca44b8Syasuoka 			break;
439a7ca44b8Syasuoka 		case NAS_PORT:
440a7ca44b8Syasuoka 			fprintf(stderr, "  <nas-port (0-65535)>\n");
441a7ca44b8Syasuoka 			break;
4425d013a5eSdlg 		case TRIES:
4435d013a5eSdlg 			fprintf(stderr, "  <tries (%u-%u)>\n",
4445d013a5eSdlg 			    TEST_TRIES_MIN, TEST_TRIES_MAX);
4455d013a5eSdlg 			break;
4465d013a5eSdlg 		case INTERVAL:
4475d013a5eSdlg 			fprintf(stderr, "  <interval (%u-%u)>\n",
4485d013a5eSdlg 			    TEST_INTERVAL_MIN, TEST_INTERVAL_MAX);
4495d013a5eSdlg 			break;
4505d013a5eSdlg 		case MAXWAIT:
4515d013a5eSdlg 			fprintf(stderr, "  <maxwait (%u-%u)>\n",
4525d013a5eSdlg 			    TEST_MAXWAIT_MIN, TEST_MAXWAIT_MAX);
4535d013a5eSdlg 			break;
454842565f2Syasuoka 		case FLAGS:
455842565f2Syasuoka 			fprintf(stderr, "  %s\n", table[i].keyword);
456842565f2Syasuoka 			break;
457842565f2Syasuoka 		case SESSION_SEQ:
458842565f2Syasuoka 			fprintf(stderr, "  <sequence number>\n");
459842565f2Syasuoka 			break;
460a852e27aSyasuoka 		case MSGAUTH:
461a852e27aSyasuoka 			fprintf(stderr, "  %s\n", table[i].keyword);
462a852e27aSyasuoka 			break;
463a7ca44b8Syasuoka 		case ENDTOKEN:
464a7ca44b8Syasuoka 			break;
465a7ca44b8Syasuoka 		}
466a7ca44b8Syasuoka 	}
467a7ca44b8Syasuoka }
468