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