1*363e4d4bSyasuoka /* $OpenBSD: parser.c,v 1.1 2012/01/18 03:13:04 yasuoka Exp $ */ 2*363e4d4bSyasuoka 3*363e4d4bSyasuoka /* This file is derived from OpenBSD:src/usr.sbin/ikectl/parser.c 1.9 */ 4*363e4d4bSyasuoka /* 5*363e4d4bSyasuoka * Copyright (c) 2010 Reyk Floeter <reyk@vantronix.net> 6*363e4d4bSyasuoka * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 7*363e4d4bSyasuoka * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 8*363e4d4bSyasuoka * 9*363e4d4bSyasuoka * Permission to use, copy, modify, and distribute this software for any 10*363e4d4bSyasuoka * purpose with or without fee is hereby granted, provided that the above 11*363e4d4bSyasuoka * copyright notice and this permission notice appear in all copies. 12*363e4d4bSyasuoka * 13*363e4d4bSyasuoka * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14*363e4d4bSyasuoka * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15*363e4d4bSyasuoka * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16*363e4d4bSyasuoka * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17*363e4d4bSyasuoka * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18*363e4d4bSyasuoka * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19*363e4d4bSyasuoka * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20*363e4d4bSyasuoka */ 21*363e4d4bSyasuoka 22*363e4d4bSyasuoka #include <sys/param.h> 23*363e4d4bSyasuoka #include <sys/socket.h> 24*363e4d4bSyasuoka #include <netinet/in.h> 25*363e4d4bSyasuoka #include <arpa/inet.h> 26*363e4d4bSyasuoka 27*363e4d4bSyasuoka #include <ctype.h> 28*363e4d4bSyasuoka #include <errno.h> 29*363e4d4bSyasuoka #include <limits.h> 30*363e4d4bSyasuoka #include <stdio.h> 31*363e4d4bSyasuoka #include <stdlib.h> 32*363e4d4bSyasuoka #include <string.h> 33*363e4d4bSyasuoka 34*363e4d4bSyasuoka #include "parser.h" 35*363e4d4bSyasuoka 36*363e4d4bSyasuoka enum token_type { 37*363e4d4bSyasuoka NOTOKEN, 38*363e4d4bSyasuoka ENDTOKEN, 39*363e4d4bSyasuoka KEYWORD, 40*363e4d4bSyasuoka PPP_ID, 41*363e4d4bSyasuoka ADDRESS, 42*363e4d4bSyasuoka INTERFACE, 43*363e4d4bSyasuoka PROTOCOL, 44*363e4d4bSyasuoka REALM, 45*363e4d4bSyasuoka USERNAME 46*363e4d4bSyasuoka }; 47*363e4d4bSyasuoka 48*363e4d4bSyasuoka struct token { 49*363e4d4bSyasuoka enum token_type type; 50*363e4d4bSyasuoka const char *keyword; 51*363e4d4bSyasuoka int value; 52*363e4d4bSyasuoka const struct token *next; 53*363e4d4bSyasuoka }; 54*363e4d4bSyasuoka 55*363e4d4bSyasuoka static struct parse_result res; 56*363e4d4bSyasuoka 57*363e4d4bSyasuoka static const struct token t_main[]; 58*363e4d4bSyasuoka static const struct token t_session[]; 59*363e4d4bSyasuoka static const struct token t_clear[]; 60*363e4d4bSyasuoka static const struct token t_filter[]; 61*363e4d4bSyasuoka static const struct token t_ppp_id[]; 62*363e4d4bSyasuoka static const struct token t_address[]; 63*363e4d4bSyasuoka static const struct token t_interface[]; 64*363e4d4bSyasuoka static const struct token t_protocol[]; 65*363e4d4bSyasuoka static const struct token t_realm[]; 66*363e4d4bSyasuoka static const struct token t_username[]; 67*363e4d4bSyasuoka 68*363e4d4bSyasuoka static const struct token t_main[] = { 69*363e4d4bSyasuoka { KEYWORD, "session", NONE, t_session }, 70*363e4d4bSyasuoka { KEYWORD, "clear", NONE, t_clear }, 71*363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL } 72*363e4d4bSyasuoka }; 73*363e4d4bSyasuoka 74*363e4d4bSyasuoka static const struct token t_session[] = { 75*363e4d4bSyasuoka { KEYWORD, "brief", SESSION_BRIEF, NULL }, 76*363e4d4bSyasuoka { KEYWORD, "packets", SESSION_PKTS, NULL }, 77*363e4d4bSyasuoka { KEYWORD, "all", SESSION_ALL, t_filter }, 78*363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL } 79*363e4d4bSyasuoka }; 80*363e4d4bSyasuoka 81*363e4d4bSyasuoka static const struct token t_clear[] = { 82*363e4d4bSyasuoka { KEYWORD, "all", CLEAR_SESSION, NULL }, 83*363e4d4bSyasuoka { KEYWORD, "ppp-id", CLEAR_SESSION, t_ppp_id }, 84*363e4d4bSyasuoka { KEYWORD, "address", CLEAR_SESSION, t_address }, 85*363e4d4bSyasuoka { KEYWORD, "interface", CLEAR_SESSION, t_interface }, 86*363e4d4bSyasuoka { KEYWORD, "protocol", CLEAR_SESSION, t_protocol }, 87*363e4d4bSyasuoka { KEYWORD, "realm", CLEAR_SESSION, t_realm }, 88*363e4d4bSyasuoka { KEYWORD, "username", CLEAR_SESSION, t_username }, 89*363e4d4bSyasuoka { ENDTOKEN, "", CLEAR_SESSION, NULL } 90*363e4d4bSyasuoka }; 91*363e4d4bSyasuoka 92*363e4d4bSyasuoka static const struct token t_filter[] = { 93*363e4d4bSyasuoka { NOTOKEN, "", NONE, NULL }, 94*363e4d4bSyasuoka { KEYWORD, "ppp-id", NONE, t_ppp_id }, 95*363e4d4bSyasuoka { KEYWORD, "address", NONE, t_address }, 96*363e4d4bSyasuoka { KEYWORD, "interface", NONE, t_interface }, 97*363e4d4bSyasuoka { KEYWORD, "protocol", NONE, t_protocol }, 98*363e4d4bSyasuoka { KEYWORD, "realm", NONE, t_realm }, 99*363e4d4bSyasuoka { KEYWORD, "username", NONE, t_username }, 100*363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL } 101*363e4d4bSyasuoka }; 102*363e4d4bSyasuoka 103*363e4d4bSyasuoka static const struct token t_ppp_id[] = { 104*363e4d4bSyasuoka { PPP_ID, "", NONE, t_filter }, 105*363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL } 106*363e4d4bSyasuoka }; 107*363e4d4bSyasuoka static const struct token t_address[] = { 108*363e4d4bSyasuoka { ADDRESS, "", NONE, t_filter }, 109*363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL } 110*363e4d4bSyasuoka }; 111*363e4d4bSyasuoka static const struct token t_interface[] = { 112*363e4d4bSyasuoka { INTERFACE, "", NONE, t_filter }, 113*363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL } 114*363e4d4bSyasuoka }; 115*363e4d4bSyasuoka static const struct token t_protocol[] = { 116*363e4d4bSyasuoka { PROTOCOL, "", NONE, t_filter }, 117*363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL } 118*363e4d4bSyasuoka }; 119*363e4d4bSyasuoka static const struct token t_realm[] = { 120*363e4d4bSyasuoka { REALM, "", NONE, t_filter }, 121*363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL } 122*363e4d4bSyasuoka }; 123*363e4d4bSyasuoka static const struct token t_username[] = { 124*363e4d4bSyasuoka { USERNAME, "", NONE, t_filter }, 125*363e4d4bSyasuoka { ENDTOKEN, "", NONE, NULL } 126*363e4d4bSyasuoka }; 127*363e4d4bSyasuoka 128*363e4d4bSyasuoka static const struct token *match_token(char *, const struct token []); 129*363e4d4bSyasuoka static void show_valid_args(const struct token []); 130*363e4d4bSyasuoka 131*363e4d4bSyasuoka struct parse_result * 132*363e4d4bSyasuoka parse(int argc, char *argv[]) 133*363e4d4bSyasuoka { 134*363e4d4bSyasuoka const struct token *table = t_main; 135*363e4d4bSyasuoka const struct token *match; 136*363e4d4bSyasuoka 137*363e4d4bSyasuoka bzero(&res, sizeof(res)); 138*363e4d4bSyasuoka 139*363e4d4bSyasuoka while (argc >= 0) { 140*363e4d4bSyasuoka if ((match = match_token(argv[0], table)) == NULL) { 141*363e4d4bSyasuoka fprintf(stderr, "valid commands/args:\n"); 142*363e4d4bSyasuoka show_valid_args(table); 143*363e4d4bSyasuoka return (NULL); 144*363e4d4bSyasuoka } 145*363e4d4bSyasuoka 146*363e4d4bSyasuoka argc--; 147*363e4d4bSyasuoka argv++; 148*363e4d4bSyasuoka 149*363e4d4bSyasuoka if (match->type == NOTOKEN || match->next == NULL) 150*363e4d4bSyasuoka break; 151*363e4d4bSyasuoka 152*363e4d4bSyasuoka table = match->next; 153*363e4d4bSyasuoka } 154*363e4d4bSyasuoka 155*363e4d4bSyasuoka if (argc > 0) { 156*363e4d4bSyasuoka fprintf(stderr, "superfluous argument: %s\n", argv[0]); 157*363e4d4bSyasuoka return (NULL); 158*363e4d4bSyasuoka } 159*363e4d4bSyasuoka 160*363e4d4bSyasuoka return (&res); 161*363e4d4bSyasuoka } 162*363e4d4bSyasuoka 163*363e4d4bSyasuoka static const struct token * 164*363e4d4bSyasuoka match_token(char *word, const struct token table[]) 165*363e4d4bSyasuoka { 166*363e4d4bSyasuoka u_int i, match = 0; 167*363e4d4bSyasuoka unsigned long int ulval; 168*363e4d4bSyasuoka const struct token *t = NULL; 169*363e4d4bSyasuoka char *ep; 170*363e4d4bSyasuoka 171*363e4d4bSyasuoka for (i = 0; table[i].type != ENDTOKEN; i++) { 172*363e4d4bSyasuoka switch (table[i].type) { 173*363e4d4bSyasuoka case NOTOKEN: 174*363e4d4bSyasuoka if (word == NULL || strlen(word) == 0) { 175*363e4d4bSyasuoka match++; 176*363e4d4bSyasuoka t = &table[i]; 177*363e4d4bSyasuoka } 178*363e4d4bSyasuoka break; 179*363e4d4bSyasuoka case KEYWORD: 180*363e4d4bSyasuoka 181*363e4d4bSyasuoka if (word != NULL && strncmp(word, table[i].keyword, 182*363e4d4bSyasuoka strlen(word)) == 0) { 183*363e4d4bSyasuoka match++; 184*363e4d4bSyasuoka t = &table[i]; 185*363e4d4bSyasuoka if (t->value) 186*363e4d4bSyasuoka res.action = t->value; 187*363e4d4bSyasuoka } 188*363e4d4bSyasuoka break; 189*363e4d4bSyasuoka case PPP_ID: 190*363e4d4bSyasuoka if (word == NULL) 191*363e4d4bSyasuoka break; 192*363e4d4bSyasuoka errno = 0; 193*363e4d4bSyasuoka ulval = strtoul(word, &ep, 10); 194*363e4d4bSyasuoka if (isdigit((unsigned char)*word) && *ep == '\0' && 195*363e4d4bSyasuoka !(errno == ERANGE && ulval == ULONG_MAX)) { 196*363e4d4bSyasuoka res.ppp_id = ulval; 197*363e4d4bSyasuoka res.has_ppp_id = 1; 198*363e4d4bSyasuoka match++; 199*363e4d4bSyasuoka t = &table[i]; 200*363e4d4bSyasuoka } 201*363e4d4bSyasuoka break; 202*363e4d4bSyasuoka case ADDRESS: 203*363e4d4bSyasuoka { 204*363e4d4bSyasuoka struct sockaddr_in sin4 = { 205*363e4d4bSyasuoka .sin_family = AF_INET, 206*363e4d4bSyasuoka .sin_len = sizeof(struct sockaddr_in) 207*363e4d4bSyasuoka }; 208*363e4d4bSyasuoka struct sockaddr_in6 sin6 = { 209*363e4d4bSyasuoka .sin6_family = AF_INET6, 210*363e4d4bSyasuoka .sin6_len = sizeof(struct sockaddr_in6) 211*363e4d4bSyasuoka }; 212*363e4d4bSyasuoka if (word == NULL) 213*363e4d4bSyasuoka break; 214*363e4d4bSyasuoka if (inet_pton(AF_INET, word, &sin4.sin_addr) == 1) 215*363e4d4bSyasuoka memcpy(&res.address, &sin4, sin4.sin_len); 216*363e4d4bSyasuoka else 217*363e4d4bSyasuoka if (inet_pton(AF_INET6, word, &sin6.sin6_addr) == 1) 218*363e4d4bSyasuoka memcpy(&res.address, &sin6, sin6.sin6_len); 219*363e4d4bSyasuoka else 220*363e4d4bSyasuoka break; 221*363e4d4bSyasuoka match++; 222*363e4d4bSyasuoka t = &table[i]; 223*363e4d4bSyasuoka } 224*363e4d4bSyasuoka break; 225*363e4d4bSyasuoka case INTERFACE: 226*363e4d4bSyasuoka if (word == NULL) 227*363e4d4bSyasuoka break; 228*363e4d4bSyasuoka res.interface = word; 229*363e4d4bSyasuoka match++; 230*363e4d4bSyasuoka t = &table[i]; 231*363e4d4bSyasuoka break; 232*363e4d4bSyasuoka case PROTOCOL: 233*363e4d4bSyasuoka if (word == NULL) 234*363e4d4bSyasuoka break; 235*363e4d4bSyasuoka if ((res.protocol = parse_protocol(word)) == 236*363e4d4bSyasuoka PROTO_UNSPEC) 237*363e4d4bSyasuoka break; 238*363e4d4bSyasuoka match++; 239*363e4d4bSyasuoka t = &table[i]; 240*363e4d4bSyasuoka break; 241*363e4d4bSyasuoka case REALM: 242*363e4d4bSyasuoka if (word == NULL) 243*363e4d4bSyasuoka break; 244*363e4d4bSyasuoka res.realm = word; 245*363e4d4bSyasuoka match++; 246*363e4d4bSyasuoka t = &table[i]; 247*363e4d4bSyasuoka break; 248*363e4d4bSyasuoka case USERNAME: 249*363e4d4bSyasuoka if (word == NULL) 250*363e4d4bSyasuoka break; 251*363e4d4bSyasuoka res.username = word; 252*363e4d4bSyasuoka match++; 253*363e4d4bSyasuoka t = &table[i]; 254*363e4d4bSyasuoka break; 255*363e4d4bSyasuoka case ENDTOKEN: 256*363e4d4bSyasuoka break; 257*363e4d4bSyasuoka } 258*363e4d4bSyasuoka } 259*363e4d4bSyasuoka 260*363e4d4bSyasuoka if (match != 1) { 261*363e4d4bSyasuoka if (word == NULL) 262*363e4d4bSyasuoka fprintf(stderr, "missing argument:\n"); 263*363e4d4bSyasuoka else if (match > 1) 264*363e4d4bSyasuoka fprintf(stderr, "ambiguous argument: %s\n", word); 265*363e4d4bSyasuoka else if (match < 1) 266*363e4d4bSyasuoka fprintf(stderr, "unknown argument: %s\n", word); 267*363e4d4bSyasuoka return (NULL); 268*363e4d4bSyasuoka } 269*363e4d4bSyasuoka 270*363e4d4bSyasuoka return (t); 271*363e4d4bSyasuoka } 272*363e4d4bSyasuoka 273*363e4d4bSyasuoka static void 274*363e4d4bSyasuoka show_valid_args(const struct token table[]) 275*363e4d4bSyasuoka { 276*363e4d4bSyasuoka int i; 277*363e4d4bSyasuoka 278*363e4d4bSyasuoka for (i = 0; table[i].type != ENDTOKEN; i++) { 279*363e4d4bSyasuoka switch (table[i].type) { 280*363e4d4bSyasuoka case NOTOKEN: 281*363e4d4bSyasuoka fprintf(stderr, " <cr>\n"); 282*363e4d4bSyasuoka break; 283*363e4d4bSyasuoka case KEYWORD: 284*363e4d4bSyasuoka fprintf(stderr, " %s\n", table[i].keyword); 285*363e4d4bSyasuoka break; 286*363e4d4bSyasuoka case PPP_ID: 287*363e4d4bSyasuoka fprintf(stderr, " <ppp-id>\n"); 288*363e4d4bSyasuoka break; 289*363e4d4bSyasuoka case ADDRESS: 290*363e4d4bSyasuoka fprintf(stderr, " <address>\n"); 291*363e4d4bSyasuoka break; 292*363e4d4bSyasuoka case INTERFACE: 293*363e4d4bSyasuoka fprintf(stderr, " <interface>\n"); 294*363e4d4bSyasuoka break; 295*363e4d4bSyasuoka case PROTOCOL: 296*363e4d4bSyasuoka fprintf(stderr, " [ pppoe | l2tp | pptp | sstp ]\n"); 297*363e4d4bSyasuoka break; 298*363e4d4bSyasuoka case REALM: 299*363e4d4bSyasuoka fprintf(stderr, " <realm>\n"); 300*363e4d4bSyasuoka break; 301*363e4d4bSyasuoka case USERNAME: 302*363e4d4bSyasuoka fprintf(stderr, " <username>\n"); 303*363e4d4bSyasuoka break; 304*363e4d4bSyasuoka case ENDTOKEN: 305*363e4d4bSyasuoka break; 306*363e4d4bSyasuoka } 307*363e4d4bSyasuoka } 308*363e4d4bSyasuoka } 309*363e4d4bSyasuoka 310*363e4d4bSyasuoka enum protocol 311*363e4d4bSyasuoka parse_protocol(const char *str) 312*363e4d4bSyasuoka { 313*363e4d4bSyasuoka return 314*363e4d4bSyasuoka (strcasecmp(str, "PPTP" ) == 0)? PPTP : 315*363e4d4bSyasuoka (strcasecmp(str, "L2TP" ) == 0)? L2TP : 316*363e4d4bSyasuoka (strcasecmp(str, "PPPoE") == 0)? PPPOE : 317*363e4d4bSyasuoka (strcasecmp(str, "SSTP" ) == 0)? SSTP : PROTO_UNSPEC; 318*363e4d4bSyasuoka } 319*363e4d4bSyasuoka 320