1/* $KAME: policy_parse.y,v 1.11 2001/08/31 09:44:18 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/types.h> 53#include <sys/param.h> 54#include <sys/socket.h> 55 56#include <netinet/in.h> 57#include <netinet/ipsec.h> 58 59#include <stdlib.h> 60#include <stdio.h> 61#include <string.h> 62#include <netdb.h> 63 64#include "ipsec_strerror.h" 65#include "libpfkey.h" 66 67#define ATOX(c) \ 68 (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) )) 69 70static caddr_t pbuf = NULL; /* sadb_x_policy buffer */ 71static int tlen = 0; /* total length of pbuf */ 72static int offset = 0; /* offset of pbuf */ 73static int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid; 74static struct sockaddr *p_src = NULL; 75static struct sockaddr *p_dst = NULL; 76 77struct _val; 78extern void yyerror __P((char *msg)); 79static struct sockaddr *parse_sockaddr __P((struct _val *buf)); 80static int rule_check __P((void)); 81static int init_x_policy __P((void)); 82static int set_x_request __P((struct sockaddr *src, struct sockaddr *dst)); 83static int set_sockaddr __P((struct sockaddr *addr)); 84static void policy_parse_request_init __P((void)); 85static caddr_t policy_parse __P((char *msg, int msglen)); 86 87extern void __policy__strbuffer__init__ __P((char *msg)); 88extern int yyparse __P((void)); 89extern int yylex __P((void)); 90 91extern char *__libyytext; /*XXX*/ 92 93%} 94 95%union { 96 u_int num; 97 struct _val { 98 int len; 99 char *buf; 100 } val; 101} 102 103%token DIR ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY 104%token IPADDRESS 105%token ME ANY 106%token SLASH HYPHEN 107%type <num> DIR ACTION PROTOCOL MODE LEVEL 108%type <val> IPADDRESS LEVEL_SPECIFY 109 110%% 111policy_spec 112 : DIR ACTION 113 { 114 p_dir = $1; 115 p_type = $2; 116 117 if (init_x_policy()) 118 return -1; 119 } 120 rules 121 | DIR 122 { 123 p_dir = $1; 124 p_type = 0; /* ignored it by kernel */ 125 126 if (init_x_policy()) 127 return -1; 128 } 129 ; 130 131rules 132 : /*NOTHING*/ 133 | rules rule { 134 if (rule_check() < 0) 135 return -1; 136 137 if (set_x_request(p_src, p_dst) < 0) 138 return -1; 139 140 policy_parse_request_init(); 141 } 142 ; 143 144rule 145 : protocol SLASH mode SLASH addresses SLASH level 146 | protocol SLASH mode SLASH addresses SLASH 147 | protocol SLASH mode SLASH addresses 148 | protocol SLASH mode SLASH 149 | protocol SLASH mode SLASH SLASH level 150 | protocol SLASH mode 151 | protocol SLASH { 152 __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 153 return -1; 154 } 155 | protocol { 156 __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 157 return -1; 158 } 159 ; 160 161protocol 162 : PROTOCOL { p_protocol = $1; } 163 ; 164 165mode 166 : MODE { p_mode = $1; } 167 ; 168 169level 170 : LEVEL { 171 p_level = $1; 172 p_reqid = 0; 173 } 174 | LEVEL_SPECIFY { 175 p_level = IPSEC_LEVEL_UNIQUE; 176 p_reqid = atol($1.buf); /* atol() is good. */ 177 } 178 ; 179 180addresses 181 : IPADDRESS { 182 p_src = parse_sockaddr(&$1); 183 if (p_src == NULL) 184 return -1; 185 } 186 HYPHEN 187 IPADDRESS { 188 p_dst = parse_sockaddr(&$4); 189 if (p_dst == NULL) 190 return -1; 191 } 192 | ME HYPHEN ANY { 193 if (p_dir != IPSEC_DIR_OUTBOUND) { 194 __ipsec_errcode = EIPSEC_INVAL_DIR; 195 return -1; 196 } 197 } 198 | ANY HYPHEN ME { 199 if (p_dir != IPSEC_DIR_INBOUND) { 200 __ipsec_errcode = EIPSEC_INVAL_DIR; 201 return -1; 202 } 203 } 204 /* 205 | ME HYPHEN ME 206 */ 207 ; 208 209%% 210 211void 212yyerror(msg) 213 char *msg; 214{ 215 fprintf(stderr, "libipsec: %s while parsing \"%s\"\n", 216 msg, __libyytext); 217 218 return; 219} 220 221static struct sockaddr * 222parse_sockaddr(buf) 223 struct _val *buf; 224{ 225 struct addrinfo hints, *res; 226 char *serv = NULL; 227 int error; 228 struct sockaddr *newaddr = NULL; 229 230 memset(&hints, 0, sizeof(hints)); 231 hints.ai_family = PF_UNSPEC; 232 hints.ai_flags = AI_NUMERICHOST; 233 error = getaddrinfo(buf->buf, serv, &hints, &res); 234 if (error != 0) { 235 yyerror("invalid IP address"); 236 __ipsec_set_strerror(gai_strerror(error)); 237 return NULL; 238 } 239 240 if (res->ai_addr == NULL) { 241 yyerror("invalid IP address"); 242 __ipsec_set_strerror(gai_strerror(error)); 243 return NULL; 244 } 245 246 newaddr = malloc(res->ai_addrlen); 247 if (newaddr == NULL) { 248 __ipsec_errcode = EIPSEC_NO_BUFS; 249 freeaddrinfo(res); 250 return NULL; 251 } 252 memcpy(newaddr, res->ai_addr, res->ai_addrlen); 253 254 freeaddrinfo(res); 255 256 __ipsec_errcode = EIPSEC_NO_ERROR; 257 return newaddr; 258} 259 260static int 261rule_check() 262{ 263 if (p_type == IPSEC_POLICY_IPSEC) { 264 if (p_protocol == IPPROTO_IP) { 265 __ipsec_errcode = EIPSEC_NO_PROTO; 266 return -1; 267 } 268 269 if (p_mode != IPSEC_MODE_TRANSPORT 270 && p_mode != IPSEC_MODE_TUNNEL) { 271 __ipsec_errcode = EIPSEC_INVAL_MODE; 272 return -1; 273 } 274 275 if (p_src == NULL && p_dst == NULL) { 276 if (p_mode != IPSEC_MODE_TRANSPORT) { 277 __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 278 return -1; 279 } 280 } 281 else if (p_src->sa_family != p_dst->sa_family) { 282 __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; 283 return -1; 284 } 285 } 286 287 __ipsec_errcode = EIPSEC_NO_ERROR; 288 return 0; 289} 290 291static int 292init_x_policy() 293{ 294 struct sadb_x_policy *p; 295 296 tlen = sizeof(struct sadb_x_policy); 297 298 pbuf = malloc(tlen); 299 if (pbuf == NULL) { 300 __ipsec_errcode = EIPSEC_NO_BUFS; 301 return -1; 302 } 303 p = (struct sadb_x_policy *)pbuf; 304 p->sadb_x_policy_len = 0; /* must update later */ 305 p->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 306 p->sadb_x_policy_type = p_type; 307 p->sadb_x_policy_dir = p_dir; 308 p->sadb_x_policy_reserved = 0; 309 offset = tlen; 310 311 __ipsec_errcode = EIPSEC_NO_ERROR; 312 return 0; 313} 314 315static int 316set_x_request(src, dst) 317 struct sockaddr *src, *dst; 318{ 319 struct sadb_x_ipsecrequest *p; 320 int reqlen; 321 322 reqlen = sizeof(*p) 323 + (src ? sysdep_sa_len(src) : 0) 324 + (dst ? sysdep_sa_len(dst) : 0); 325 tlen += reqlen; /* increment to total length */ 326 327 pbuf = realloc(pbuf, tlen); 328 if (pbuf == NULL) { 329 __ipsec_errcode = EIPSEC_NO_BUFS; 330 return -1; 331 } 332 p = (struct sadb_x_ipsecrequest *)&pbuf[offset]; 333 p->sadb_x_ipsecrequest_len = reqlen; 334 p->sadb_x_ipsecrequest_proto = p_protocol; 335 p->sadb_x_ipsecrequest_mode = p_mode; 336 p->sadb_x_ipsecrequest_level = p_level; 337 p->sadb_x_ipsecrequest_reqid = p_reqid; 338 offset += sizeof(*p); 339 340 if (set_sockaddr(src) || set_sockaddr(dst)) 341 return -1; 342 343 __ipsec_errcode = EIPSEC_NO_ERROR; 344 return 0; 345} 346 347static int 348set_sockaddr(addr) 349 struct sockaddr *addr; 350{ 351 if (addr == NULL) { 352 __ipsec_errcode = EIPSEC_NO_ERROR; 353 return 0; 354 } 355 356 /* tlen has already incremented */ 357 358 memcpy(&pbuf[offset], addr, sysdep_sa_len(addr)); 359 360 offset += sysdep_sa_len(addr); 361 362 __ipsec_errcode = EIPSEC_NO_ERROR; 363 return 0; 364} 365 366static void 367policy_parse_request_init() 368{ 369 p_protocol = IPPROTO_IP; 370 p_mode = IPSEC_MODE_ANY; 371 p_level = IPSEC_LEVEL_DEFAULT; 372 p_reqid = 0; 373 if (p_src != NULL) { 374 free(p_src); 375 p_src = NULL; 376 } 377 if (p_dst != NULL) { 378 free(p_dst); 379 p_dst = NULL; 380 } 381 382 return; 383} 384 385static caddr_t 386policy_parse(msg, msglen) 387 char *msg; 388 int msglen; 389{ 390 int error; 391 pbuf = NULL; 392 tlen = 0; 393 394 /* initialize */ 395 p_dir = IPSEC_DIR_INVALID; 396 p_type = IPSEC_POLICY_DISCARD; 397 policy_parse_request_init(); 398 __policy__strbuffer__init__(msg); 399 400 error = yyparse(); /* it must be set errcode. */ 401 if (error) { 402 if (pbuf != NULL) 403 free(pbuf); 404 return NULL; 405 } 406 407 /* update total length */ 408 ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen); 409 410 __ipsec_errcode = EIPSEC_NO_ERROR; 411 412 return pbuf; 413} 414 415caddr_t 416ipsec_set_policy(msg, msglen) 417 char *msg; 418 int msglen; 419{ 420 caddr_t policy; 421 422 policy = policy_parse(msg, msglen); 423 if (policy == NULL) { 424 if (__ipsec_errcode == EIPSEC_NO_ERROR) 425 __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 426 return NULL; 427 } 428 429 __ipsec_errcode = EIPSEC_NO_ERROR; 430 return policy; 431} 432 433