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