xref: /openbsd-src/usr.sbin/radiusctl/parser.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: parser.c,v 1.1 2015/07/21 04:06:04 yasuoka Exp $	*/
2 
3 /*
4  * Copyright (c) 2010 Reyk Floeter <reyk@vantronix.net>
5  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
6  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "parser.h"
27 
28 enum token_type {
29 	NOTOKEN,
30 	KEYWORD,
31 	HOSTNAME,
32 	SECRET,
33 	USERNAME,
34 	PASSWORD,
35 	PORT,
36 	METHOD,
37 	NAS_PORT,
38 	ENDTOKEN
39 };
40 
41 struct token {
42 	enum token_type		 type;
43 	const char		*keyword;
44 	int			 value;
45 	const struct token	*next;
46 };
47 
48 static struct parse_result res;
49 
50 static const struct token t_test[];
51 static const struct token t_secret[];
52 static const struct token t_username[];
53 static const struct token t_test_opts[];
54 static const struct token t_password[];
55 static const struct token t_port[];
56 static const struct token t_method[];
57 static const struct token t_nas_port[];
58 
59 static const struct token t_main[] = {
60 	{ KEYWORD,	"test",		TEST,		t_test },
61 	{ ENDTOKEN,	"",		NONE,		NULL }
62 };
63 
64 static const struct token t_test[] = {
65 	{ HOSTNAME,	"",		NONE,		t_secret },
66 	{ ENDTOKEN,	"",		NONE,		NULL }
67 };
68 
69 static const struct token t_secret[] = {
70 	{ SECRET,	"",		NONE,		t_username },
71 	{ ENDTOKEN,	"",		NONE,		NULL }
72 };
73 
74 static const struct token t_username[] = {
75 	{ USERNAME,	"",		NONE,		t_test_opts },
76 	{ ENDTOKEN,	"",		NONE,		NULL }
77 };
78 
79 static const struct token t_test_opts[] = {
80 	{ NOTOKEN,	"",		NONE,		NULL },
81 	{ KEYWORD,	"password",	NONE,		t_password },
82 	{ KEYWORD,	"port",		NONE,		t_port },
83 	{ KEYWORD,	"method",	NONE,		t_method },
84 	{ KEYWORD,	"nas-port",	NONE,		t_nas_port },
85 	{ ENDTOKEN,	"",		NONE,		NULL }
86 };
87 
88 static const struct token t_password[] = {
89 	{ PASSWORD,	"",		NONE,		t_test_opts },
90 	{ ENDTOKEN,	"",		NONE,		NULL }
91 };
92 
93 static const struct token t_port[] = {
94 	{ PORT,		"",		NONE,		t_test_opts },
95 	{ ENDTOKEN,	"",		NONE,		NULL }
96 };
97 
98 static const struct token t_method[] = {
99 	{ METHOD,	"",		NONE,		t_test_opts },
100 	{ ENDTOKEN,	"",		NONE,		NULL }
101 };
102 
103 static const struct token t_nas_port[] = {
104 	{ NAS_PORT,	"",		NONE,		t_test_opts },
105 	{ ENDTOKEN,	"",		NONE,		NULL }
106 };
107 
108 
109 static const struct token	*match_token(char *, const struct token []);
110 static void			 show_valid_args(const struct token []);
111 
112 struct parse_result *
113 parse(int argc, char *argv[])
114 {
115 	const struct token	*table = t_main;
116 	const struct token	*match;
117 
118 	bzero(&res, sizeof(res));
119 
120 	while (argc >= 0) {
121 		if ((match = match_token(argv[0], table)) == NULL) {
122 			fprintf(stderr, "valid commands/args:\n");
123 			show_valid_args(table);
124 			return (NULL);
125 		}
126 
127 		argc--;
128 		argv++;
129 
130 		if (match->type == NOTOKEN || match->next == NULL)
131 			break;
132 
133 		table = match->next;
134 	}
135 
136 	if (argc > 0) {
137 		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
138 		return (NULL);
139 	}
140 
141 	return (&res);
142 }
143 
144 static const struct token *
145 match_token(char *word, const struct token table[])
146 {
147 	u_int			 i, match = 0;
148 	const struct token	*t = NULL;
149 	long long		 num;
150 	const char		*errstr;
151 
152 	for (i = 0; table[i].type != ENDTOKEN; i++) {
153 		switch (table[i].type) {
154 		case NOTOKEN:
155 			if (word == NULL || strlen(word) == 0) {
156 				match++;
157 				t = &table[i];
158 			}
159 			break;
160 		case KEYWORD:
161 			if (word != NULL && strncmp(word, table[i].keyword,
162 			    strlen(word)) == 0) {
163 				match++;
164 				t = &table[i];
165 				if (t->value)
166 					res.action = t->value;
167 			}
168 			break;
169 		case HOSTNAME:
170 			if (word == NULL)
171 				break;
172 			match++;
173 			res.hostname = word;
174 			t = &table[i];
175 			break;
176 		case SECRET:
177 			if (word == NULL)
178 				break;
179 			match++;
180 			res.secret = word;
181 			t = &table[i];
182 			break;
183 		case USERNAME:
184 			if (word == NULL)
185 				break;
186 			match++;
187 			res.username = word;
188 			t = &table[i];
189 			break;
190 		case PASSWORD:
191 			if (word == NULL)
192 				break;
193 			match++;
194 			res.password = word;
195 			t = &table[i];
196 			break;
197 		case PORT:
198 			if (word == NULL)
199 				break;
200 			num = strtonum(word, 1, UINT16_MAX, &errstr);
201 			if (errstr != NULL) {
202 				fprintf(stderr,
203 				    "invalid argument: %s is %s for \"port\"\n",
204 				    word, errstr);
205 				return (NULL);
206 			}
207 			match++;
208 			res.port = num;
209 			t = &table[i];
210 			break;
211 		case METHOD:
212 			if (word == NULL)
213 				break;
214 			if (strcasecmp(word, "pap") == 0)
215 				res.auth_method = PAP;
216 			else if (strcasecmp(word, "chap") == 0)
217 				res.auth_method = CHAP;
218 			else if (strcasecmp(word, "mschapv2") == 0)
219 				res.auth_method = MSCHAPV2;
220 			else {
221 				fprintf(stderr,
222 				    "invalid argument: %s for \"method\"\n",
223 				    word);
224 				return (NULL);
225 			}
226 			match++;
227 			t = &table[i];
228 			break;
229 		case NAS_PORT:
230 			if (word == NULL)
231 				break;
232 			num = strtonum(word, 0, 65535, &errstr);
233 			if (errstr != NULL) {
234 				fprintf(stderr,
235 				    "invalid argument: %s is %s for "
236 				    "\"nas-port\"\n", word, errstr);
237 				return (NULL);
238 			}
239 			match++;
240 			res.nas_port = num;
241 			t = &table[i];
242 			break;
243 		case ENDTOKEN:
244 			break;
245 		}
246 	}
247 
248 	if (match != 1) {
249 		if (word == NULL)
250 			fprintf(stderr, "missing argument:\n");
251 		else if (match > 1)
252 			fprintf(stderr, "ambiguous argument: %s\n", word);
253 		else if (match < 1)
254 			fprintf(stderr, "unknown argument: %s\n", word);
255 		return (NULL);
256 	}
257 
258 	return (t);
259 }
260 
261 static void
262 show_valid_args(const struct token table[])
263 {
264 	int	i;
265 
266 	for (i = 0; table[i].type != ENDTOKEN; i++) {
267 		switch (table[i].type) {
268 		case NOTOKEN:
269 			fprintf(stderr, "  <cr>\n");
270 			break;
271 		case KEYWORD:
272 			fprintf(stderr, "  %s\n", table[i].keyword);
273 			break;
274 		case HOSTNAME:
275 			fprintf(stderr, "  <hostname>\n");
276 			break;
277 		case SECRET:
278 			fprintf(stderr, "  <radius secret>\n");
279 			break;
280 		case USERNAME:
281 			fprintf(stderr, "  <username>\n");
282 			break;
283 		case PASSWORD:
284 			fprintf(stderr, "  <password>\n");
285 			break;
286 		case PORT:
287 			fprintf(stderr, "  <port number>\n");
288 			break;
289 		case METHOD:
290 			fprintf(stderr, "  <auth method (pap, chap, "
291 			    "mschapv2)>\n");
292 			break;
293 		case NAS_PORT:
294 			fprintf(stderr, "  <nas-port (0-65535)>\n");
295 			break;
296 		case ENDTOKEN:
297 			break;
298 		}
299 	}
300 }
301