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