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 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 yylex(void); 92 93 extern char *__libipsecyytext; /*XXX*/ 94 95 %} 96 97 %union { 98 u_int num; 99 struct _val { 100 int len; 101 char *buf; 102 } val; 103 } 104 105 %token DIR ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY 106 %token IPADDRESS 107 %token ME ANY 108 %token SLASH HYPHEN 109 %type <num> DIR ACTION PROTOCOL MODE LEVEL 110 %type <val> IPADDRESS LEVEL_SPECIFY 111 112 %% 113 policy_spec 114 : DIR ACTION 115 { 116 p_dir = $1; 117 p_type = $2; 118 119 if (init_x_policy()) 120 return -1; 121 } 122 rules 123 | DIR 124 { 125 p_dir = $1; 126 p_type = 0; /* ignored it by kernel */ 127 128 if (init_x_policy()) 129 return -1; 130 } 131 ; 132 133 rules 134 : /*NOTHING*/ 135 | rules rule { 136 if (rule_check() < 0) 137 return -1; 138 139 if (set_x_request(p_src, p_dst) < 0) 140 return -1; 141 142 policy_parse_request_init(); 143 } 144 ; 145 146 rule 147 : protocol SLASH mode SLASH addresses SLASH level 148 | protocol SLASH mode SLASH addresses SLASH 149 | protocol SLASH mode SLASH addresses 150 | protocol SLASH mode SLASH 151 | protocol SLASH mode SLASH SLASH level 152 | protocol SLASH mode 153 | protocol SLASH { 154 __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 155 return -1; 156 } 157 | protocol { 158 __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 159 return -1; 160 } 161 ; 162 163 protocol 164 : PROTOCOL { p_protocol = $1; } 165 ; 166 167 mode 168 : MODE { p_mode = $1; } 169 ; 170 171 level 172 : LEVEL { 173 p_level = $1; 174 p_reqid = 0; 175 } 176 | LEVEL_SPECIFY { 177 p_level = IPSEC_LEVEL_UNIQUE; 178 p_reqid = atol($1.buf); /* atol() is good. */ 179 } 180 ; 181 182 addresses 183 : IPADDRESS { 184 p_src = parse_sockaddr(&$1); 185 if (p_src == NULL) 186 return -1; 187 } 188 HYPHEN 189 IPADDRESS { 190 p_dst = parse_sockaddr(&$4); 191 if (p_dst == NULL) 192 return -1; 193 } 194 | ME HYPHEN ANY { 195 if (p_dir != IPSEC_DIR_OUTBOUND) { 196 __ipsec_errcode = EIPSEC_INVAL_DIR; 197 return -1; 198 } 199 } 200 | ANY HYPHEN ME { 201 if (p_dir != IPSEC_DIR_INBOUND) { 202 __ipsec_errcode = EIPSEC_INVAL_DIR; 203 return -1; 204 } 205 } 206 /* 207 | ME HYPHEN ME 208 */ 209 ; 210 211 %% 212 213 void 214 yyerror(char *msg) 215 { 216 fprintf(stderr, "libipsec: %s while parsing \"%s\"\n", 217 msg, __libipsecyytext); 218 219 return; 220 } 221 222 static struct sockaddr * 223 parse_sockaddr(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_addr->sa_len); 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_addr->sa_len); 253 254 freeaddrinfo(res); 255 256 __ipsec_errcode = EIPSEC_NO_ERROR; 257 return newaddr; 258 } 259 260 static int 261 rule_check(void) 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 291 static int 292 init_x_policy(void) 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 memset(pbuf, 0, tlen); 304 p = (struct sadb_x_policy *)pbuf; 305 p->sadb_x_policy_len = 0; /* must update later */ 306 p->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 307 p->sadb_x_policy_type = p_type; 308 p->sadb_x_policy_dir = p_dir; 309 p->sadb_x_policy_id = 0; 310 311 offset = tlen; 312 313 __ipsec_errcode = EIPSEC_NO_ERROR; 314 return 0; 315 } 316 317 static int 318 set_x_request(struct sockaddr *src, struct sockaddr *dst) 319 { 320 struct sadb_x_ipsecrequest *p; 321 int reqlen; 322 323 reqlen = sizeof(*p) 324 + (src ? src->sa_len : 0) 325 + (dst ? dst->sa_len : 0); 326 tlen += reqlen; /* increment to total length */ 327 328 pbuf = realloc(pbuf, tlen); 329 if (pbuf == NULL) { 330 __ipsec_errcode = EIPSEC_NO_BUFS; 331 return -1; 332 } 333 p = (struct sadb_x_ipsecrequest *)&pbuf[offset]; 334 p->sadb_x_ipsecrequest_len = reqlen; 335 p->sadb_x_ipsecrequest_proto = p_protocol; 336 p->sadb_x_ipsecrequest_mode = p_mode; 337 p->sadb_x_ipsecrequest_level = p_level; 338 p->sadb_x_ipsecrequest_reqid = p_reqid; 339 offset += sizeof(*p); 340 341 if (set_sockaddr(src) || set_sockaddr(dst)) 342 return -1; 343 344 __ipsec_errcode = EIPSEC_NO_ERROR; 345 return 0; 346 } 347 348 static int 349 set_sockaddr(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, addr->sa_len); 359 360 offset += addr->sa_len; 361 362 __ipsec_errcode = EIPSEC_NO_ERROR; 363 return 0; 364 } 365 366 static void 367 policy_parse_request_init(void) 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 385 static caddr_t 386 policy_parse(char *msg, int msglen) 387 { 388 int error; 389 pbuf = NULL; 390 tlen = 0; 391 392 /* initialize */ 393 p_dir = IPSEC_DIR_INVALID; 394 p_type = IPSEC_POLICY_DISCARD; 395 policy_parse_request_init(); 396 __policy__strbuffer__init__(msg); 397 398 error = yyparse(); /* it must be set errcode. */ 399 __policy__strbuffer__free__(); 400 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 415 caddr_t 416 ipsec_set_policy(char *msg, int msglen) 417 { 418 caddr_t policy; 419 420 policy = policy_parse(msg, msglen); 421 if (policy == NULL) { 422 if (__ipsec_errcode == EIPSEC_NO_ERROR) 423 __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 424 return NULL; 425 } 426 427 __ipsec_errcode = EIPSEC_NO_ERROR; 428 return policy; 429 } 430 431