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