1 /* $KAME: policy_parse.y,v 1.14 2003/06/27 03:39:20 itojun Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * IN/OUT bound policy configuration take place such below: 34 * in <policy> 35 * out <policy> 36 * 37 * <policy> is one of following: 38 * "discard", "none", "ipsec <requests>", "entrust", "bypass", 39 * 40 * The following requests are accepted as <requests>: 41 * 42 * protocol/mode/src-dst/level 43 * protocol/mode/src-dst parsed as protocol/mode/src-dst/default 44 * protocol/mode/src-dst/ parsed as protocol/mode/src-dst/default 45 * protocol/transport parsed as protocol/mode/any-any/default 46 * protocol/transport//level parsed as protocol/mode/any-any/level 47 * 48 * You can concatenate these requests with either ' '(single space) or '\n'. 49 */ 50 51 %{ 52 #include <sys/cdefs.h> 53 __FBSDID("$FreeBSD$"); 54 55 #include <sys/types.h> 56 #include <sys/param.h> 57 #include <sys/socket.h> 58 59 #include <netinet/in.h> 60 #include <netipsec/ipsec.h> 61 62 #include <stdlib.h> 63 #include <stdio.h> 64 #include <string.h> 65 #include <netdb.h> 66 67 #include "ipsec_strerror.h" 68 69 #define ATOX(c) \ 70 (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) )) 71 72 static caddr_t pbuf = NULL; /* sadb_x_policy buffer */ 73 static int tlen = 0; /* total length of pbuf */ 74 static int offset = 0; /* offset of pbuf */ 75 static int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid; 76 static struct sockaddr *p_src = NULL; 77 static struct sockaddr *p_dst = NULL; 78 79 struct _val; 80 extern void yyerror(char *msg); 81 static struct sockaddr *parse_sockaddr(struct _val *buf); 82 static int rule_check(void); 83 static int init_x_policy(void); 84 static int set_x_request(struct sockaddr *src, struct sockaddr *dst); 85 static int set_sockaddr(struct sockaddr *addr); 86 static void policy_parse_request_init(void); 87 static caddr_t policy_parse(char *msg, int msglen); 88 89 extern void __policy__strbuffer__init__(char *msg); 90 extern void __policy__strbuffer__free__(void); 91 extern int yyparse(void); 92 extern int yylex(void); 93 94 extern char *__libipsecyytext; /*XXX*/ 95 96 %} 97 98 %union { 99 u_int num; 100 struct _val { 101 int len; 102 char *buf; 103 } val; 104 } 105 106 %token DIR ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY 107 %token IPADDRESS 108 %token ME ANY 109 %token SLASH HYPHEN 110 %type <num> DIR ACTION PROTOCOL MODE LEVEL 111 %type <val> IPADDRESS LEVEL_SPECIFY 112 113 %% 114 policy_spec 115 : DIR ACTION 116 { 117 p_dir = $1; 118 p_type = $2; 119 120 if (init_x_policy()) 121 return -1; 122 } 123 rules 124 | DIR 125 { 126 p_dir = $1; 127 p_type = 0; /* ignored it by kernel */ 128 129 if (init_x_policy()) 130 return -1; 131 } 132 ; 133 134 rules 135 : /*NOTHING*/ 136 | rules rule { 137 if (rule_check() < 0) 138 return -1; 139 140 if (set_x_request(p_src, p_dst) < 0) 141 return -1; 142 143 policy_parse_request_init(); 144 } 145 ; 146 147 rule 148 : protocol SLASH mode SLASH addresses SLASH level 149 | protocol SLASH mode SLASH addresses SLASH 150 | protocol SLASH mode SLASH addresses 151 | protocol SLASH mode SLASH 152 | protocol SLASH mode SLASH SLASH level 153 | protocol SLASH mode 154 | protocol SLASH { 155 __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 156 return -1; 157 } 158 | protocol { 159 __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 160 return -1; 161 } 162 ; 163 164 protocol 165 : PROTOCOL { p_protocol = $1; } 166 ; 167 168 mode 169 : MODE { p_mode = $1; } 170 ; 171 172 level 173 : LEVEL { 174 p_level = $1; 175 p_reqid = 0; 176 } 177 | LEVEL_SPECIFY { 178 p_level = IPSEC_LEVEL_UNIQUE; 179 p_reqid = atol($1.buf); /* atol() is good. */ 180 } 181 ; 182 183 addresses 184 : IPADDRESS { 185 p_src = parse_sockaddr(&$1); 186 if (p_src == NULL) 187 return -1; 188 } 189 HYPHEN 190 IPADDRESS { 191 p_dst = parse_sockaddr(&$4); 192 if (p_dst == NULL) 193 return -1; 194 } 195 | ME HYPHEN ANY { 196 if (p_dir != IPSEC_DIR_OUTBOUND) { 197 __ipsec_errcode = EIPSEC_INVAL_DIR; 198 return -1; 199 } 200 } 201 | ANY HYPHEN ME { 202 if (p_dir != IPSEC_DIR_INBOUND) { 203 __ipsec_errcode = EIPSEC_INVAL_DIR; 204 return -1; 205 } 206 } 207 /* 208 | ME HYPHEN ME 209 */ 210 ; 211 212 %% 213 214 void 215 yyerror(msg) 216 char *msg; 217 { 218 fprintf(stderr, "libipsec: %s while parsing \"%s\"\n", 219 msg, __libipsecyytext); 220 221 return; 222 } 223 224 static struct sockaddr * 225 parse_sockaddr(buf) 226 struct _val *buf; 227 { 228 struct addrinfo hints, *res; 229 char *serv = NULL; 230 int error; 231 struct sockaddr *newaddr = NULL; 232 233 memset(&hints, 0, sizeof(hints)); 234 hints.ai_family = PF_UNSPEC; 235 hints.ai_flags = AI_NUMERICHOST; 236 error = getaddrinfo(buf->buf, serv, &hints, &res); 237 if (error != 0) { 238 yyerror("invalid IP address"); 239 __ipsec_set_strerror(gai_strerror(error)); 240 return NULL; 241 } 242 243 if (res->ai_addr == NULL) { 244 yyerror("invalid IP address"); 245 __ipsec_set_strerror(gai_strerror(error)); 246 return NULL; 247 } 248 249 newaddr = malloc(res->ai_addr->sa_len); 250 if (newaddr == NULL) { 251 __ipsec_errcode = EIPSEC_NO_BUFS; 252 freeaddrinfo(res); 253 return NULL; 254 } 255 memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len); 256 257 freeaddrinfo(res); 258 259 __ipsec_errcode = EIPSEC_NO_ERROR; 260 return newaddr; 261 } 262 263 static int 264 rule_check() 265 { 266 if (p_type == IPSEC_POLICY_IPSEC) { 267 if (p_protocol == IPPROTO_IP) { 268 __ipsec_errcode = EIPSEC_NO_PROTO; 269 return -1; 270 } 271 272 if (p_mode != IPSEC_MODE_TRANSPORT 273 && p_mode != IPSEC_MODE_TUNNEL) { 274 __ipsec_errcode = EIPSEC_INVAL_MODE; 275 return -1; 276 } 277 278 if (p_src == NULL && p_dst == NULL) { 279 if (p_mode != IPSEC_MODE_TRANSPORT) { 280 __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 281 return -1; 282 } 283 } 284 else if (p_src->sa_family != p_dst->sa_family) { 285 __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; 286 return -1; 287 } 288 } 289 290 __ipsec_errcode = EIPSEC_NO_ERROR; 291 return 0; 292 } 293 294 static int 295 init_x_policy() 296 { 297 struct sadb_x_policy *p; 298 299 tlen = sizeof(struct sadb_x_policy); 300 301 pbuf = malloc(tlen); 302 if (pbuf == NULL) { 303 __ipsec_errcode = EIPSEC_NO_BUFS; 304 return -1; 305 } 306 memset(pbuf, 0, tlen); 307 p = (struct sadb_x_policy *)pbuf; 308 p->sadb_x_policy_len = 0; /* must update later */ 309 p->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 310 p->sadb_x_policy_type = p_type; 311 p->sadb_x_policy_dir = p_dir; 312 p->sadb_x_policy_id = 0; 313 314 offset = tlen; 315 316 __ipsec_errcode = EIPSEC_NO_ERROR; 317 return 0; 318 } 319 320 static int 321 set_x_request(src, dst) 322 struct sockaddr *src, *dst; 323 { 324 struct sadb_x_ipsecrequest *p; 325 int reqlen; 326 327 reqlen = sizeof(*p) 328 + (src ? src->sa_len : 0) 329 + (dst ? dst->sa_len : 0); 330 tlen += reqlen; /* increment to total length */ 331 332 pbuf = realloc(pbuf, tlen); 333 if (pbuf == NULL) { 334 __ipsec_errcode = EIPSEC_NO_BUFS; 335 return -1; 336 } 337 p = (struct sadb_x_ipsecrequest *)&pbuf[offset]; 338 p->sadb_x_ipsecrequest_len = reqlen; 339 p->sadb_x_ipsecrequest_proto = p_protocol; 340 p->sadb_x_ipsecrequest_mode = p_mode; 341 p->sadb_x_ipsecrequest_level = p_level; 342 p->sadb_x_ipsecrequest_reqid = p_reqid; 343 offset += sizeof(*p); 344 345 if (set_sockaddr(src) || set_sockaddr(dst)) 346 return -1; 347 348 __ipsec_errcode = EIPSEC_NO_ERROR; 349 return 0; 350 } 351 352 static int 353 set_sockaddr(addr) 354 struct sockaddr *addr; 355 { 356 if (addr == NULL) { 357 __ipsec_errcode = EIPSEC_NO_ERROR; 358 return 0; 359 } 360 361 /* tlen has already incremented */ 362 363 memcpy(&pbuf[offset], addr, addr->sa_len); 364 365 offset += addr->sa_len; 366 367 __ipsec_errcode = EIPSEC_NO_ERROR; 368 return 0; 369 } 370 371 static void 372 policy_parse_request_init() 373 { 374 p_protocol = IPPROTO_IP; 375 p_mode = IPSEC_MODE_ANY; 376 p_level = IPSEC_LEVEL_DEFAULT; 377 p_reqid = 0; 378 if (p_src != NULL) { 379 free(p_src); 380 p_src = NULL; 381 } 382 if (p_dst != NULL) { 383 free(p_dst); 384 p_dst = NULL; 385 } 386 387 return; 388 } 389 390 static caddr_t 391 policy_parse(msg, msglen) 392 char *msg; 393 int msglen; 394 { 395 int error; 396 pbuf = NULL; 397 tlen = 0; 398 399 /* initialize */ 400 p_dir = IPSEC_DIR_INVALID; 401 p_type = IPSEC_POLICY_DISCARD; 402 policy_parse_request_init(); 403 __policy__strbuffer__init__(msg); 404 405 error = yyparse(); /* it must be set errcode. */ 406 __policy__strbuffer__free__(); 407 408 if (error) { 409 if (pbuf != NULL) 410 free(pbuf); 411 return NULL; 412 } 413 414 /* update total length */ 415 ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen); 416 417 __ipsec_errcode = EIPSEC_NO_ERROR; 418 419 return pbuf; 420 } 421 422 caddr_t 423 ipsec_set_policy(msg, msglen) 424 char *msg; 425 int msglen; 426 { 427 caddr_t policy; 428 429 policy = policy_parse(msg, msglen); 430 if (policy == NULL) { 431 if (__ipsec_errcode == EIPSEC_NO_ERROR) 432 __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 433 return NULL; 434 } 435 436 __ipsec_errcode = EIPSEC_NO_ERROR; 437 return policy; 438 } 439 440