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